目录
3. 有界阻塞队列——ArrayBlockingQueue和LinkedBlockingQueue
4. 优先无界阻塞队列——PriorityBlockingQueue
BlockingQueue是java.util.concurrent包中定义的一个阻塞队列的接口,concurrent包中实现了多种阻塞队列,它们都实现了该接口。有了这些阻塞队列,可以更好的实现多线程之间的数据共享;而如果能灵活运用这些类,便可以在工作中更好的实现高质量的多线程高并发程序。本章首先从BlockingQueue接口开始,详细分析了concurrent包中的这些阻塞队列的实现。
1. BlockingQueue接口
BlockingQueue接口继承了Queue接口,所以其本身也可以作为一般的队列使用。在此基础上,BlockingQueue定义了如下几个阻塞方法:
-
void put(E e) throws InterruptedException; 该方法为阻塞式入队方法,如果发生中断异常会抛出。
-
boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException; 该方法为阻塞式入队方法,该方法可以设置一个超时时间,当发生超时时可返回false表示入队失败。
-
E take() throws InterruptedException; 该方法为阻塞式出队方法,如果发生中断异常会抛出。
-
E poll(long timeout, TimeUnit unit) throws InterruptedException; 该方法为阻塞式出对方法,该方法也可以设置一个超时时间,如果发生超时,将会返回null。
2. BlockingQueue的分类
concurrent包中定义了多种阻塞队列:
- ArrayBlockingQueue:有界阻塞队列,通过数组实现,在创建对象时必须指定该队列的容量。
- LinkedBlockingQueue:有界阻塞队列,通过链表实现,在创建对象时可以指定该队列的容量,如果不指定容量默认为Integer类型的最大值。
- PriorityBlockingQueue:无界阻塞队列,可指定初始容量,可指定队列的优先级。
- SynchronousQueue:同步阻塞队列,该阻塞队列比较特殊,其不存储元素,如果该队列中有一个元素,则其他线程不能再往里面插入元素;只有等消费者线程消费之后才能继续插入元素,反之也是一样。
- DelayQueue:延时阻塞队列,该队列可设置延时,入队的元素只有在延时期满之后才能消费。
- LinkedTransferQueue:无界阻塞队列,通过链表实现,相比其他队列,该队列多了两个方法transfer()和tryTransfer()。
- LinkedBlockingDeque:双向阻塞队列,该队列也是通过链表实现,多线程并发时可将锁竞争缩减一半。
本节将concurrent包中所有的阻塞队列的特点进行了简要的概括,下文将详细分析每种阻塞队列的实现原理与使用场景等。
3. 有界阻塞队列——ArrayBlockingQueue和LinkedBlockingQueue
concurrent包实现了两种有界阻塞队列:ArrayBlockingQueue和LinkedBlockingQueue,顾名思义,ArrayBlockingQueue通过数组实现阻塞队列,LinkedBlockingQueue则通过链表实现阻塞队列。两者的实现方案类似,因此,在此以ArrayBlockingQueue为例,介绍有界阻塞队列的实现原理。
在ArrayBlockingQueue中定义了两个方法用来为阻塞队列插入和删除元素。
private void enqueue(E x) {
// assert lock.getHoldCount() == 1;
// assert items[putIndex] == null;
final Object[] items = this.items;
items[putIndex] = x;
if (++putIndex == items.length)
putIndex = 0;
count++;