【多线程研究专题二】【Condtion使用实例】ArrayBlockingQueue解析
来源:互联网 发布:tesla model s 知乎 编辑:程序博客网 时间:2024/05/16 20:29
在研究Condition时,发现它的API提供了BoudedBuffer实现,并指出ArrayBlockingQueue就是一个BoudedBuffer的高阶实现。
因此深入研究了下BoudedBuffer,其核心思想是:
1. 使用一个循环数组
2. 定义一个Count,作为put和take的次数差值约束,并使得put次数-take次数的差值为 0 - Capacity。达到边界的线程,就进入waiting状态,这样的目的是避免数组坐标越界。
正文:
Condtion的API有如下例子,实现了BoundedBuffer,并指出,ArrayBlockingQueue就是这样实现的,所以没必要自己实现,直接用ArrayBlockingQueue即可。
A
Condition
instance is intrinsically bound to a lock. To obtain a Condition
instance for a particular Lock
instance use its newCondition()
method.As an example, suppose we have a bounded buffer which supports put
and take
methods. If a take
is attempted on an empty buffer, then the thread will block until an item becomes available; if a put
is attempted on a full buffer, then the thread will block until a space becomes available. We would like to keep waiting put
threads and take
threads in separate wait-sets so that we can use the optimization of only notifying a single thread at a time when items or spaces become available in the buffer. This can be achieved using two Condition
instances.
class BoundedBuffer { final Lock lock = new ReentrantLock(); final Condition notFull = lock.newCondition(); final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[100]; int putptr, takeptr, count; public void put(Object x) throws InterruptedException { lock.lock(); try { while (count == items.length) notFull.await(); items[putptr] = x; if (++putptr == items.length) putptr = 0; ++count; notEmpty.signal(); } finally { lock.unlock(); } } public Object take() throws InterruptedException { lock.lock(); try { while (count == 0) notEmpty.await(); Object x = items[takeptr]; if (++takeptr == items.length) takeptr = 0; --count; notFull.signal(); return x; } finally { lock.unlock(); } } }
(The
ArrayBlockingQueue
class provides this functionality, so there is no reason to implement this sample usage class.)package condtion;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ArrayBlockingQueueTest {
//ArrayBlockingQueue 和 BouderyBuffer 的循环数组使用同样的容量
static final int Capacity = 5;
public static void main(String[] args) {
// ArrayBlockingQueue的主要框架就是BoudedBuffer。
ArrayBlockingQueue blockQueue1 = new ArrayBlockingQueue<>(Capacity);
// 看看BoundedBuffer的执行效果
BoundedBuffer blockQueue2 = new BoundedBuffer();
// 在这个例子,入参可以替换,只是循环数组的容量不一样,效果有所不同
// blockQueue1/blockQueue2
Runnable taskPut = new RunnablePut(blockQueue2);
Runnable taskTake = new RunnableTake(blockQueue2);
new Thread(taskPut).start();
new Thread(taskTake).start();
}
static class RunnableTake<T> implements Runnable {
T queue;
public RunnableTake(T blockQueue2) {
queue = blockQueue2;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
int result = 0;
if (queue instanceof BoundedBuffer) {
result = (int) ((BoundedBuffer) queue).take();
} else {
result = (int) ((ArrayBlockingQueue) queue).take();
}
System.out.printf("take result = %d\r\n", result);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
static class RunnablePut<T> implements Runnable {
T queue;
public RunnablePut(T blockQueue2) {
queue = blockQueue2;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
System.out.printf("goint to put : %d\r\n", i);
if (queue instanceof BoundedBuffer) {
((BoundedBuffer) queue).put(i);
} else {
((ArrayBlockingQueue) queue).put(i);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
static class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[Capacity];
//ptr作用:读写数组的数据。疑问:如何确保数据不被重复读取?
int putptr, takeptr;
/* count作用:
* 前提说明: items是一个循环数组,默认容量是5,实例从Object[0] - Object[4]。
* 从而限定了put和take的操作的次数差值只能为[0-5],避免xxxptr越界操作。
*
* count == 0. 说明take和put的操作次数相等
* count == 5. 说明put的次数等于5。这是循环数组items[5]的极限.
* count > 5 . 说明put的操作次数比take次数超出5次,而循环数组大小是5,说明有数据还没来得及被take就被覆盖了。
* count < 0 . 说明take操作比put还多,表示take获取到了还没put的数据。
* 因为>5和<0的情况是不允许的,因此count的边界是0-5.在这两个值出现的时候,进行Condition条件等待。
*/
int count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length) {
System.out.println("Queue is Fullded");
notFull.await();
}
items[putptr] = x;
if (++putptr == items.length) {
putptr = 0;
}
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0) {
System.out.println("Queue is Empty");
notEmpty.await();
}
Object x = items[takeptr];
if (++takeptr == items.length) {
takeptr = 0;
}
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}
}
0 0
- 【多线程研究专题二】【Condtion使用实例】ArrayBlockingQueue解析
- 【多线程研究专题一】【Condition使用实例】Conditon与Lock的关系
- 多线程之ArrayBlockingQueue的使用
- ArrayBlockingQueue解析
- ArrayBlockingQueue使用
- Java多线程--并发中集合的使用之ArrayBlockingQueue
- ArrayBlockingQueue调度多线程demo
- 多线程-队列ArrayBlockingQueue 、LinkedBlockingQueue
- ArrayBlockingQueue源代码及解析
- ArrayBlockingQueue源代码及解析
- ArrayBlockingQueue源码解析
- ArrayBlockingQueue源码解析
- ArrayBlockingQueue源码解析
- Delphi多线程实例解析
- Java多线程-实例解析
- Java多线程-实例解析
- Java多线程-实例解析
- 多线程函数实例解析
- 学会“投机取巧”——Redis之父九条忠告,如何成为“一打十”的程序员
- 【计算机视觉】 opencv双目视觉 立体视觉 三维重建
- 输出单层结点
- datagrid footer 列出指定行之和
- Oracle 12c 多租户 CDB 与 PDB之 shared undo 与 Local undo 切换
- 【多线程研究专题二】【Condtion使用实例】ArrayBlockingQueue解析
- 动态网页开发基础
- 一些常用的存图数据结构
- linux tcp/ip 分析---1
- 从用户需求演进的角度看大数据与人工智能
- JS设计模式之代理模式
- Keil5代码自动补全设置
- pwntools 简单用法
- 百钱百鸡