美文网首页JUC并发相关
26. 并发终结之BlockingQueue

26. 并发终结之BlockingQueue

作者: 涣涣虚心0215 | 来源:发表于2020-09-27 10:20 被阅读0次

线程池里面最重要的还有个并发容器,即阻塞队列BlockingQueue。
BlockingQueue是阻塞队列的接口,提供了常见的几种方法:

方法 抛出异常 返回值 阻塞 超时(阻塞一段时间)
插入方法 add offer put offer(time)
移除方法 remove poll take poll(time)
检查方法 element peek N/A N/A

BlockingQueue是不接受null值的,当add, put, offer一个null值,会抛出NullPointerException。当poll操作没有元素可以返回的时候,return的是null值。

  1. 抛出异常:当队列满时,如果再往队列里插入元素(add),会抛出IllegalStateException("Queuefull")异常。当队列空时,从队列里获取元素(remove)会抛出NoSuchElementException异常。
  2. 返回值:当往队列插入元素时,会返回元素是否插入(offer)成功,成功返回true。如果是移除方法(poll),则是从队列里取出一个元素,如果没有则返回null
  3. 一直阻塞:当阻塞队列满时,如果生产者线程往队列里put元素,队列会一直阻塞生产者线程,直到队列可用或者响应中断退出。当队列空时,如果消费者线程从队列里take元素,队列会阻塞住消费者线程,直到队列不为空。
  4. 超时退出:当阻塞队列满时,如果生产者线程往队列里插入元素,队列会阻塞生产者线程一段时间,如果超过了指定的时间,生产者线程就会退出。

常见的阻塞队列:

  1. ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。适合生产者和消费者并发较小的情况。
    按照先进先出原则,要求设定初始大小;内部使用预先分配大小的数组作为其存储空间,put和take操作不会增加垃圾回收的负担。
    问题在于其put和take操作使用的是同一个锁(显式锁),从而会导致锁的高竞争,导致更多的上线文切换。

  2. LinkedBlockingQueue:一个由链表结构组成的无界阻塞队列。适合生产者和消费者并发较大的情况。
    按照先进先出原则,可以不设定初始大小,最大为Integer.Max_Value(2^31 - 1),优点是put和take分别采用了两个显式锁(putLock和takeLock)。
    问题是其内部是通过链表实现,put和take会导致链表节点的动态创建和删除,增加垃圾回收的负担。

  3. PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。(PriorityQueue不是线程安全的)
    默认情况下,按照自然顺序,要么实现compareTo()方法,指定构造参数Comparator。

  4. DelayQueue:一个使用优先级队列实现(内部基于PriorityQueue)的无界阻塞队列。
    支持延时获取的元素的阻塞队列,元素必须要实现Delayed接口。适用场景:实现自己的缓存系统,订单到期,限时支付等等。
    DelayQueue是一个无界阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部是延迟期满后保存时间最长的Delayed 元素。

  5. SynchronousQueue:一个不存储元素的阻塞队列。
    每一个put操作都要等待一个take操作
    SynchronousQueue在线程池里使用的时候,是使用缓存空间的,线程池提交不上去,则会创建新的工作线程来处理任务,所以必须限制max_pool_size。

相关文章

网友评论

    本文标题:26. 并发终结之BlockingQueue

    本文链接:https://www.haomeiwen.com/subject/pkjkyktx.html