A blocking queue is a queue that blocks when you try to dequeue from it and the queue is empty, or if you try to enqueue items to it and the queue is already full. A thread trying to dequeue from an empty queue is blocked until some other thread inserts an item into the queue. A thread trying to enqueue an item in a full queue is blocked until some other thread makes space in the queue, either by dequeuing one or more items or clearing the queue completely.
阻塞队列是一个队列:
情况1:希望出队,但队为空 【直到其他线程将元素入队,才结束阻塞】
情况2:希望入队,但队为满 【直到其他线程将元素出队,才结束阻塞】
Here is a diagram showing two threads cooperating via a blocking queue:
A BlockingQueue with one thread putting into it, and another thread taking from it.
Java 5 comes with blocking queue implementations in the java.util.concurrent package. You can read about that class in my java.util.concurrent.BlockingQueue tutorial. Even if Java 5 comes with a blocking queue implementation, it can be useful to know the theory behind their implementation.
阻塞队列实现是在java.util.concurrent.BlockingQueue ,这是接口
Blocking Queue Implementation
The implementation of a blocking queue looks similar to a Bounded Semaphore. Here is a simple implementation of a blocking queue:
blocking queue的实现类似于Bounded Semaphore。
public class BlockingQueue {
private List queue = new LinkedList();
private int limit = 10;
public BlockingQueue(int limit){
this.limit = limit;
}
//入队
public synchronized void enqueue(Object item)
throws InterruptedException {
while(this.queue.size() == this.limit) {
wait(); //等待有元素出队
}
//此时queue.size()<limit 也就是有空位,从而不用等待,直接入队
this.queue.add(item);
if(this.queue.size() == 1) {
//说明之前的队是空的,现在有元素了,从而让之前因没元素无法出队的线程执行
notifyAll();
}
}
public synchronized Object dequeue()
throws InterruptedException{
while(this.queue.size() == 0){
wait(); //等待有元素入队
}
if(this.queue.size() == this.limit){
//因为此时堆满,若出队,则queue.size()<limit,从而可以让其他线程入队notifyAll()
notifyAll();
}
//若0<queue.size()<limit,则说明队伍有元素,可以直接出队。
return this.queue.remove(0);
}
}
Notice how notifyAll() is only called from enqueue() and dequeue() if the queue size is equal to the size bounds (0 or limit). If the queue size is not equal to either bound when enqueue() or dequeue() is called, there can be no threads waiting to either enqueue or dequeue items.
请注意,如果队列大小等于大小界限(0或限制),则仅从enqueue()和dequeue()调用notifyAll()的方式。 如果在调用enqueue()或dequeue()时队列大小不等于绑定的大小,则没有线程等待入队或出队。
Java BlockingQueue Example
以下是基于典型的生产者-使用者场景的一个用例。注意,BlockingQueue 可以安全地与多个生产者和多个使用者一起使用。
class Producer implements Runnable {
private final BlockingQueue queue;
Producer(BlockingQueue q) { queue = q; }
public void run() {
try {
/*
produce()方法是线程私有,所以它与线程是一一对应的
quequ.put()是线程安全的,其放入队列的对象是唯一的。
*/
while(true) { queue.put(produce()); }
} catch (InterruptedException ex) { ... handle ...}
}
Object produce() { ... }
}
class Consumer implements Runnable {
private final BlockingQueue queue;
Consumer(BlockingQueue q) { queue = q; }
public void run() {
try {
/*
queue.take()是线程安全的 也就是某个线程取出一个元素时,其他线程不会对这个元素进行取出更
改等操作 Consumer是线程私有的,所以consume()并不用加synchronized
*/
while(true) { consume(queue.take()); }
} catch (InterruptedException ex) { ... handle ...}
}
void consume(Object x) { ... }
}
class Setup {
void main() {
BlockingQueue q = new SomeQueueImplementation();
Producer p = new Producer(q);
Consumer c1 = new Consumer(q);
Consumer c2 = new Consumer(q);
new Thread(p).start();
new Thread(c1).start();
new Thread(c2).start();
}
}