关于ArrayBlockingQueue可以看这篇文章:
深入剖析java并发之阻塞队列LinkedBlockingQueue与ArrayBlockingQueue
下面就仿照ArrayBlockingQueue,写个简易版的阻塞队列MyArrayBlockingQueue:
/**
* 自定义的 阻塞队列
*
* @param <T> 需要的对象类型
*/
public class MyArrayBlockingQueue<T> {
/**
* 对象数组,存对象
*/
private final T[] items;
/**
* 锁
*/
private Lock lock = new ReentrantLock();
/**
* 基于lock的 队列没有满 的条件。
* 用于:队列满时 阻塞(await()),不满时唤醒(signal())
*/
private Condition notFull = lock.newCondition();
/**
* 基于lock的 队列没有空 的条件。
* 用于:队列空时 阻塞(await()),不空时唤醒(signal())
*/
private Condition notEmpty = lock.newCondition();
/**
* 队列中数据的数量
*/
private int count;
/**
* 待存的数据的位置
*/
private int putIndex;
/**
* 待取的数据的位置
*/
private int taskIndex;
private String TAG = "MyArrayBlockingQueue";
public MyArrayBlockingQueue(int size) {
items = (T[]) new Object[size];
}
public void put(T t) {
lock.lock();
try {
while (count == items.length) {
//已经是满的,阻塞等待“不满”的线程
Log.i(TAG, "put: 已满,等待中~");
notFull.await();
}
Log.i(TAG, "put: 不满,插入~");
items[putIndex] = t;
if (++putIndex == items.length) {
putIndex = 0;
}
count++;
//已经确定不空了,唤醒 阻塞着的 等待“不空”的线程
notEmpty.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public T take() {
lock.lock();
T t = null;
try {
while (count == 0) {
//已经是空的,阻塞等待“不空”的线程
Log.i(TAG, "take: 空的,等待中~");
notEmpty.await();
}
Log.i(TAG, "take: 不空,取出~");
t = items[taskIndex];
if (++taskIndex == items.length) {
taskIndex = 0;
}
count--;
//已经确定不满了,唤醒 阻塞着的 等待“不满”的线程
notFull.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
return t;
}
}
然后是创建生产者、消费者,即两个线程:
/**
* 生产者线程
*/
private class ConsumerThread extends Thread {
private final MyArrayBlockingQueue<Apple> arrayBlockingQueue;
public ConsumerThread(MyArrayBlockingQueue<Apple> arrayBlockingQueue) {
this.arrayBlockingQueue = arrayBlockingQueue;
}
@Override
public void run() {
while (true) {
try {
Log.i(TAG, "run: take, begin");
Apple apple = arrayBlockingQueue.take();
Log.i(TAG, "run: take, apple=" + apple);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 生产者线程
*/
private class ProducerThread extends Thread {
private final MyArrayBlockingQueue<Apple> arrayBlockingQueue;
public ProducerThread(MyArrayBlockingQueue<Apple> arrayBlockingQueue) {
this.arrayBlockingQueue = arrayBlockingQueue;
}
@Override
public void run() {
try {
Thread.sleep(2000);
while (true) {
Apple apple = new Apple();
Log.i(TAG, "run: put, begin");
arrayBlockingQueue.put(apple);
Log.i(TAG, "run: put, apple=" + apple);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 产品
*/
private class Apple {
}
下面是使用MyArrayBlockingQueue实现“生产者-消费者”模式:
/**
* 生产者-消费者 模式
* 实现方法:使用 {@Link MyArrayBlockingQueue}
*/
private void threadTest4() {
MyArrayBlockingQueue<Apple> arrayBlockingQueue = new MyArrayBlockingQueue<Apple>(3);
new ProducerThread(arrayBlockingQueue).start();
new ConsumerThread(arrayBlockingQueue).start();
}
结果:
07-15 22:17:53.700 4835-5172/com.hfy.demo00 I/MainActivityhfy: run: take, begin--没有apple,消费者阻塞
07-15 22:17:55.701 4835-5171/com.hfy.demo00 I/MainActivityhfy: run: put, begin
07-15 22:17:55.702 4835-5171/com.hfy.demo00 I/MainActivityhfy: run: put, apple=com.hfy.demo00.MainActivity$Apple@5cd7457
run: put, begin
07-15 22:17:55.702 4835-5171/com.hfy.demo00 I/MainActivityhfy: run: put, apple=com.hfy.demo00.MainActivity$Apple@4373b44
run: put, begin
07-15 22:17:55.703 4835-5171/com.hfy.demo00 I/MainActivityhfy: run: put, apple=com.hfy.demo00.MainActivity$Apple@a2b242d
run: put, begin
07-15 22:17:55.704 4835-5172/com.hfy.demo00 I/MainActivityhfy: run: take, apple=com.hfy.demo00.MainActivity$Apple@5cd7457 --有apple了,消费者消费
07-15 22:17:55.704 4835-5171/com.hfy.demo00 I/MainActivityhfy: run: put, apple=com.hfy.demo00.MainActivity$Apple@1324d62
run: put, begin --队列满了,生产者阻塞
07-15 22:17:56.704 4835-5172/com.hfy.demo00 I/MainActivityhfy: run: take, begin
07-15 22:17:56.705 4835-5172/com.hfy.demo00 I/MainActivityhfy: run: take, apple=com.hfy.demo00.MainActivity$Apple@4373b44
07-15 22:17:56.705 4835-5171/com.hfy.demo00 I/MainActivityhfy: run: put, apple=com.hfy.demo00.MainActivity$Apple@1cafef3 --没满,插入