目录
一、什么是阻塞队列
对于许多线程问题,可以通过使用一个或多个队列以优雅且安全的方式将其形式化。生产者线程向队列插入元素,消费者线程则取出它们。使用队列,可以安全地从一个线程向另一个线程传递数据(不需要考虑同步)。
阻塞队列(Blocking Queue)和非阻塞队列的区别:当试图向队列添加元素而队列已满,或是想从队列移出元素而队列为空的时候,阻塞队列(blocking queue)导致线程阻塞。(他们都是线程安全的,不用考虑线程同步问题)
阻塞队列会自动地平衡负载。如果第一个线程集运行得比第二个慢,第二个线程集在等待结果时会阻塞。如果第一个线程集运行得快,它将等待第二个队列集赶上来。作为使用者,我们无需关心什么时候阻塞线程,什么时候唤醒线程。
二、阻塞队列的分类
阻塞队列方法分为以下3类,这取决于当队列满或空时它们的响应方式。如果将队列当作线程管理工具来使用,将要用到put和take方法。当试图向满的队列中添加或从空的队列中移出元素时,add、remove和element操作抛出异常。当然,在一个多线程程序中,队列会在任何时候空或满,因此,一定要使用offer、poll和peek方法作为替代。这些方法如果不能完成任务,只是给出一个错误提示而不会抛出异常。
方法 | 正常动作 | 特殊情况下的动作 |
add | 添加一个元素 | 如果队列满,则抛出IllegalStateException异常 |
element | 返回队列的头元素 | 如果队列空,抛出NoSuchElementException异常 |
remove | 移出并返回头元素 | 如果队列空,则抛出NoSuchElementException异常 |
offer | 添加一个元素并返回true | 如果队列满,返回false |
peek | 返回队列的头元素 | 如果队列空,则返回null |
poll | 移出并返回队列的头元素 | 如果队列空,则返回null |
put | 添加一个元素 | 如果队列满,则阻塞 |
take | 移出并返回头元素 | 如果队列空,则阻塞 |
ps:poll和peek方法返回空来指示失败。因此,向这些队列中插入null值是非法的;还有带有超时的offer方法和poll方法的变体。
三、常见的BlockingQueue
1、LinkedBlockingQueue
LinkedBlockingQueue是基于链表实现的一个阻塞队列,默认情况下容量是没有上边界的,但是,也可以选择指定最大容量。先进先出。
2、ArrayBlockingQueue
ArrayBlockingQueue是基于循环数组实现的一个阻塞队列,在构造时需要指定容量,并且有一个可选的参数来指定是否需要公平性。若设置了公平参数,那么等待了最长时间的线程会优先得到处理。通常,公平性会降低性能,只有在确实非常需要时才使用它。默认非公平,先进先出。有界的数组可以防止资源耗尽问题。
3、PriorityBlockingQueue
PriorityBlockingQueue是基于堆实现的一个阻塞队列,它是一个带优先级的队列,而不是先进先出队列。元素按照它们的优先级顺序被移出。该队列是没有容量上限,但是,如果队列是空的,取元素的操作会阻塞。
4、SynchronousQuene
一个不缓存任务的阻塞队列,生产者放入一个任务必须等到消费者取出这个任务。也就是说新任务进来时,不会缓存,而是直接被调度执行该任务,如果没有可用线程,则创建新线程,如果线程数量达到maxPoolSize,则执行拒绝策略。
5、DelayQueue
DelayQueue包含实现Delayed接口的对象:
interface Delayed extends Comparable<Delayed> {
long getDelay(TimeUnit unit);
}
getDelay方法返回对象的残留延迟。负值表示延迟已经结束。元素只有在延迟用完的情况下才能从DelayQueue移除。还必须实现compareTo方法。DelayQueue使用该方法对元素进行排序。
6、TransferQueue
Java SE 7增加了一个TransferQueue接口,允许生产者线程等待,直到消费者准备就绪可以接收一个元素。如果生产者调用
q.transfer(item);
这个调用会阻塞,直到另一个线程将元素(item)删除。LinkedTransferQueue类实现了这个接口。
四、例子
https://blog.csdn.net/qq_33248299/article/details/78869105
参考:《Java核心技术 卷I》
https://blog.csdn.net/yudiandemingzi/article/details/82318390