JAVA API中这样解释BlockingQueue:
支持两个附加操作的 Queue
,这两个操作是:获取元素时等待队列变为非空,以及存储元素时等待空间变得可用。
BlockingQueue 方法以四种形式出现,对于不能立即满足但可能在将来某一时刻可以满足的操作,这四种形式的处理方式不同:第一种是抛出一个异常,第二种是返回一个特殊值(null 或false,具体取决于操作),第三种是在操作可以成功前,无限期地阻塞当前线程,第四种是在放弃前只在给定的最大时间限制内阻塞。下表中总结了这些方法:
抛出异常 | 特殊值 | 阻塞 | 超时 | |
插入 | add(e) | offer(e) | put(e) | offer(e, time, unit) |
移除 | remove() | poll() | take() | poll(time, unit) |
检查 | element() | peek() | 不可用 | 不可用 |
BlockingQueue 不接受 null 元素。试图 add、put 或 offer 一个 null 元素时,某些实现会抛出 NullPointerException。null 被用作指示poll 操作失败的警戒值。
先看一个简单的实现例子:
public 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();
}
}
}
上面的例子展示了一个定长的队列,提供了存放和提取数据的方法,且使用ReentrantLock来实现同步。
再来看看SUN的实现:
private static final long serialVersionUID = -817911632652898426L;
private final E[] items;
private int takeIndex;
private int putIndex;
private int count;
private final ReentrantLock lock;
private final Condition notEmpty;
private final Condition notFull;
public ArrayBlockingQueue(int paramInt)
{
this(paramInt, false);
}
//初始构造函数
public ArrayBlockingQueue(int paramInt, boolean paramBoolean)
{
if (paramInt <= 0)
throw new IllegalArgumentException();
this.items = ((Object[])new Object[paramInt]);
//初始化锁对象
this.lock = new ReentrantLock(paramBoolean);
this.notEmpty = this.lock.newCondition();
this.notFull = this.lock.newCondition();
}
//put的实现
public void put(E paramE)
throws InterruptedException
{
if (paramE == null)
throw new NullPointerException();
Object[] arrayOfObject = this.items;
ReentrantLock localReentrantLock = this.lock;
//如果当前线程未被中断则获取锁
localReentrantLock.lockInterruptibly();
try
{
try
{
while (this.count == arrayOfObject.length)
//数组已满 等待直到被唤醒或中断
this.notFull.await();
}
catch (InterruptedException localInterruptedException)
{
//被中断则唤醒
this.notFull.signal();
throw localInterruptedException;
}
insert(paramE);
}
finally
{
localReentrantLock.unlock();
}
}
private void insert(E paramE)
{
this.items[this.putIndex] = paramE;
this.putIndex = inc(this.putIndex);
this.count += 1;
//唤醒持有notEmpty等待的线程
this.notEmpty.signal();
}
public E take()
throws InterruptedException
{
ReentrantLock localReentrantLock = this.lock;
//获取锁
localReentrantLock.lockInterruptibly();
try
{
try
{
while (this.count == 0)
//空则等待
this.notEmpty.await();
}
catch (InterruptedException localInterruptedException)
{
//唤醒
this.notEmpty.signal();
throw localInterruptedException;
}
Object localObject1 = extract();
Object localObject2 = localObject1;
return localObject2;
}
finally
{
localReentrantLock.unlock();
}
}
private E extract()
{
Object[] arrayOfObject = this.items;
Object localObject = arrayOfObject[this.takeIndex];
arrayOfObject[this.takeIndex] = null;
this.takeIndex = inc(this.takeIndex);
this.count -= 1;
//唤醒等待的线程
this.notFull.signal();
return localObject;
}
public ArrayBlockingQueue(int paramInt)
{
this(paramInt, false);
}
//初始构造函数
public ArrayBlockingQueue(int paramInt, boolean paramBoolean)
{
if (paramInt <= 0)
throw new IllegalArgumentException();
this.items = ((Object[])new Object[paramInt]);
//初始化锁对象
this.lock = new ReentrantLock(paramBoolean);
this.notEmpty = this.lock.newCondition();
this.notFull = this.lock.newCondition();
}
//put的实现
public void put(E paramE)
throws InterruptedException
{
if (paramE == null)
throw new NullPointerException();
Object[] arrayOfObject = this.items;
ReentrantLock localReentrantLock = this.lock;
//如果当前线程未被中断则获取锁
localReentrantLock.lockInterruptibly();
try
{
try
{
while (this.count == arrayOfObject.length)
//数组已满 等待直到被唤醒或中断
this.notFull.await();
}
catch (InterruptedException localInterruptedException)
{
//被中断则唤醒
this.notFull.signal();
throw localInterruptedException;
}
insert(paramE);
}
finally
{
localReentrantLock.unlock();
}
}
private void insert(E paramE)
{
this.items[this.putIndex] = paramE;
this.putIndex = inc(this.putIndex);
this.count += 1;
//唤醒持有notEmpty等待的线程
this.notEmpty.signal();
}
public E take()
throws InterruptedException
{
ReentrantLock localReentrantLock = this.lock;
//获取锁
localReentrantLock.lockInterruptibly();
try
{
try
{
while (this.count == 0)
//空则等待
this.notEmpty.await();
}
catch (InterruptedException localInterruptedException)
{
//唤醒
this.notEmpty.signal();
throw localInterruptedException;
}
Object localObject1 = extract();
Object localObject2 = localObject1;
return localObject2;
}
finally
{
localReentrantLock.unlock();
}
}
private E extract()
{
Object[] arrayOfObject = this.items;
Object localObject = arrayOfObject[this.takeIndex];
arrayOfObject[this.takeIndex] = null;
this.takeIndex = inc(this.takeIndex);
this.count -= 1;
//唤醒等待的线程
this.notFull.signal();
return localObject;
}
以上只贴出了部分源码,ArrayBlockingQueue还提供了其他三种处理方式,有兴趣的可以自己去研读。
下面是一个小例子:
public class Setup {
class Producer implements Runnable {
volatile int i=0;
private final BlockingQueue<String> queue;
public Producer(BlockingQueue<String> q) { queue = q; }
public void run() {
try {
while(true&&i<1000) {
queue.put(produce());
}
} catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
String produce(){
i++;
return "put"+i;
}
}
class Consumer implements Runnable {
private final BlockingQueue<String> queue;
Consumer(BlockingQueue<String> q) { queue = q; }
public void run() {
try {
while(true) {
synchronized (lock) {
System.out.println(queue.take());
}
}
} catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
}
Object lock = new Object();
public static void main(String args[]){
Setup s = new Setup();
BlockingQueue<String> q = new ArrayBlockingQueue<String>(1);
Producer p = s.new Producer(q);
Consumer c1 = s.new Consumer(q);
Consumer c2 = s.new Consumer(q);
new Thread(p).start();
new Thread(c1).start();
new Thread(c2).start();
}
}