阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞。试图从空的阻塞队列中获取元素的线程将会被阻塞,直到其他的线程往空的队列插入新的元素。同样,试图往已满的阻塞队列中添加新元素的线程同样也会被阻塞,直到其他的线程使队列重新变得空闲起来,如从队列中移除一个或者多个元素,或者完全清空队列。
下图展示了如何通过阻塞队列来合作:
线程1往阻塞队列中添加元素,而线程2从阻塞队列中移除元素
BlockingQueue 方法以四种形式出现,对于不能立即满足但可能在将来某一时刻可以满足的操作,这四种形式的处理方式不同:
- 第一种是抛出一个异常。
- 第二种是返回一个特殊值(null 或 false,具体取决于操作)。
- 第三种是在操作可以成功前,无限期地阻塞当前线程。
- 第四种是在放弃前只在给定的最大时间限制内阻塞。
下表中总结了这些方法:
含有方法解释:
boolean add(E e)
将指定元素插入此队列中,成功时返回 true,如果当前队列已满没有可用的空间,无法插入,则抛出 IllegalStateException。boolean offer(E e)
将指定元素插入此队列中,成功时返回 true,如果当前队列已满没有可用的空间,无法插入,则返回 false。void put(E e)
将指定元素插入此队列中,将等待可用的空间,进入阻塞状态。boolean remove(Object o)
从此队列中移除指定元素的单个实例。E peek()
获取但不移除此队列的头;如果此队列为空,则返回 null。E element()
获取但是不移除此队列的头。此方法与 peek 唯一的不同在于:此队列为空时将抛出一个异常。E poll()
获取并移除此队列的头,如果此队列为空,则返回 null。E take()
获取并移除此队列的头部,在元素变得可用之前一直等待(如果有必要)。
示例:
import java.util.concurrent.ArrayBlockingQueue;
/**
* 测试双缓冲队列 FIFO(先进先出)
*/
public class CopyOfTestBlockingQueue {
private int queueSize = 10;
private ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<String>(queueSize);
public static void main(String[] args) {
CopyOfTestBlockingQueue test = new CopyOfTestBlockingQueue();
Producer producer = test.new Producer();
Consumer consumer = test.new Consumer();
producer.start();
consumer.start();
}
class Consumer extends Thread {
@Override
public void run() {
consume();
}
private void consume() {
while (true) {
try {
String s = queue.take(); //获取并移除此队列的头部,在元素变得可用之前一直等待
System.out.println("从队列中取出:"+s+",队列剩余" + queue.size() + "个元素");
Thread.sleep((int)(Math.random()*1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Producer extends Thread {
int i = 0;
@Override
public void run() {
produce();
}
private void produce() {
while (true) {
try {
queue.put("元素"+(++i)); //将指定的元素插入此队列的尾部,如果该队列已满,则等待可用的空间。
System.out.println("向队列中插入:元素"+i+",队列剩余空间:" + (queueSize - queue.size()));
Thread.sleep((int)(Math.random()*1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
结果:
从队列中取出:元素1,队列剩余0个元素
向队列中插入:元素1,队列剩余空间:10
向队列中插入:元素2,队列剩余空间:9
从队列中取出:元素2,队列剩余0个元素
向队列中插入:元素3,队列剩余空间:9
从队列中取出:元素3,队列剩余0个元素
从队列中取出:元素4,队列剩余0个元素
向队列中插入:元素4,队列剩余空间:10
向队列中插入:元素5,队列剩余空间:9
向队列中插入:元素6,队列剩余空间:8
从队列中取出:元素5,队列剩余1个元素
从队列中取出:元素6,队列剩余0个元素
向队列中插入:元素7,队列剩余空间:9
向队列中插入:元素8,队列剩余空间:8
向队列中插入:元素9,队列剩余空间:7
向队列中插入:元素10,队列剩余空间:6
从队列中取出:元素7,队列剩余3个元素
从队列中取出:元素8,队列剩余2个元素
向队列中插入:元素11,队列剩余空间:7