4-14-阻塞队列

文章目录
  1. 1. 阻塞队列(线程安全)
    1. 1.1. 非阻塞队列
      1. 1.1.1. concurrent*的lock-free
    2. 1.2. 阻塞队列脑图
    3. 1.3. 阻塞的意思
      1. 1.3.1. 1.队列没数据,消费端阻塞
      2. 1.3.2. 2.队列满,生产端阻塞
    4. 1.4. 主要方法
    5. 1.5. 1.array数组结构有界全局锁(初始化时必须指定大小)
    6. 1.6. 2.linked单链表结构无界两锁(可指定大小)
    7. 1.7. 3.priority优先级排序数组扩容无界
    8. 1.8. 4.delay优先级队列实现的无界
    9. 1.9. 5.synchronous不存储元素(newCachedThreadPool默认队列)
    10. 1.10. 6.LinkedTransferQueue链表无界,预占
    11. 1.11. 7.LinkedBlockingDeque双向链表,队头队尾均可加减,工作窃取(锁竞争最多降到一半)
      1. 1.11.1. 适用场景
    12. 1.12. array和linked的比较

阻塞队列(线程安全)

非阻塞队列

  1. 线程安全的Queue可以分为阻塞队列和非阻塞队列,其中阻塞队列的典型例子是BlockingQueue,非阻塞队列的典型例子是ConcurrentLinkedQueue。
  2. 线程安全就是说多线程访问同一代码,不会产生不确定的结果。

image-20210712152546088

concurrent*的lock-free

有时候我们把并发包下的所有容器都习惯的称为并发容器,但是严格来讲,只有Concurrent*才是真的并发容器。

关于问题中的区别在于:

Concurrent类型基于lock-free,在常见的多线程访问场景,一般可以提供较高吞吐量。
lock-free:如果在一个共享的数据结构上的操作都不需要互斥,那么它是无锁的。如果一个进程在操作中间被中断,其它进程不受影响。
举例:如果一个线程拥有互斥锁,当运行线程的时候处于休眠,就会block,但lock-free模式下不会阻塞。

LinkedBlockingQueue内部是基于锁,提供BlockingQueue等特性方法
同样是线程安全的容器,可简单认为:

Concurrent类型没有类似CopyOnWrite之类的容器相对较重的修改开销

Concurrent拥有较低的遍历一致性,也就是弱一致性。当使用遍历方法中的迭代器遍历时,容器发生修改,迭代器仍然可以继续遍历
注:与弱一致性相对的,如果遍历过程出了问题,就会抛出异常ConcurrentModifcationException,停止遍历。

concurrent的弱一致性,导致对size的操作精准度有限。

concurrent读取性能不佳。
————————————————
版权声明:本文为CSDN博主「2NaCl」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_41936805/article/details/96307821

阻塞队列脑图

image-20210712152546088

阻塞的意思

1.队列没数据,消费端阻塞

2.队列满,生产端阻塞

主要方法

image-20210708154950772

特殊值指回复null or false。

详细的解释:https://blog.csdn.net/org_hjh/article/details/110195517

image-20210708160441368

1.array数组结构有界全局锁(初始化时必须指定大小)

arrayBlockingQueue

默认不公平锁,创建一个公平锁的阻塞队列:

1
ArrayBlockingQueue fairQueue = new ArrayBlockingQueue(1000,true);

2.linked单链表结构无界两锁(可指定大小)

linkedBlockingQueue

  1. 对于生产者端和消费者端分别采用了独立的锁来控制数据同步。LinkedBlockingQueue是由链表组成操作的分别是头尾节点,相互竞争的关系较小。而ArrayBlockingQueue是数组,添加和删除都是在同一个数组上,虽然也可以用两个锁但是实现上需要更多的控制。
  2. LinkedBlockingQueue 会默认一个类似无限大小的容量(Integer.MAX_VALUE)。

3.priority优先级排序数组扩容无界

PriorityBlockingQueue 优先级队列,线程安全(添加、读取都进行了加锁)、无界、读阻塞的队列,底层采用的堆结构实现(二叉树),默认是小根堆,最小的或者最大的元素会一直置顶,每次获取都取最顶端的数据。可以实现优先出队。最特别的是它只有一个锁,入队操作永远成功,而出队只有在空队列的时候才会进行线程阻塞。可以说有一定的应用场景吧,比如:有任务要执行,可以对任务加一个优先级的权重,这样队列会识别出来,对该任务优先进行出队。

元素采取自然顺序升序排列。可以自定义实现compareTo()方法来指定元素进行排序规则,或者初始化 PriorityBlockingQueue 时,指定构造参数 Comparator 来对元素进行排序。需要注意的是不能保证同优先级元素的顺序。

4.delay优先级队列实现的无界

内部使用优先队列(PriorityQueue)实现,而无界队列基于数组的扩容实现。在创建元素时,可以指定多久才能从队列中获取当前元素。只有延时期满后才能从队列中获取元素。

应用场景:

  1. 缓存设计,有效期控制
  2. 定时任务调度,保存当天执行任务和执行时间

5.synchronous不存储元素(newCachedThreadPool默认队列)

SynchronousQueue 的吞吐量高于LinkedBlockingQueue 和ArrayBlockingQueue。

相对比较另类的SynchronousQueue,在Java 6中,其实现发生了非常大的变化,利用CAS替换掉了原本基于锁的逻辑,同步开销比较小。它 是Executors.newCachedThreadPool()的默认队列。

原因:

  1. 不像ArrayBlockingQueue、LinkedBlockingDeque之类的阻塞队列依赖AQS实现并发操作,SynchronousQueue直接使用CAS实现线程的安全访问。(自旋可以显著改变吞吐量。)

6.LinkedTransferQueue链表无界,预占

有就拿货走人,没有就占个位置,等到或超时。

7.LinkedBlockingDeque双向链表,队头队尾均可加减,工作窃取(锁竞争最多降到一半)

Deque 是 Double ended queue (双端队列) 的缩写,读音和 deck 一样,蛋壳。

双端队列同样适用于另一种相关模式,即工作密取。在生产者-消费者设计中,所有消费者有一个共享的工作队列,而在工作密取设计中,每个消费者都有各自的双端队列。如果一个消费者完成了自己双端队列中的全部工作,那么它可以从其它消费者双端队列末尾秘密地获取工作。密取工作模式比传统的生产者-消费者模式具有更高的可伸缩性,这是因为工作者线程不会在单个共享的任务队列上发生竞争。在大多数时候,它们都只是访问自己的双端队列,从而极大地减少了竞争。当工作者线程需要访问另一个队列时,它会从队列的尾部而不是头部获取工作,因此进一步降低了队列上的竞争程度。

适用场景

工作密取非常适用于即是消费者也是生产者问题。

当执行某个工作时可能导致出现更多的工作。

例如,在网页爬虫程序中处理一个页面时,通常会发现有更多的页面需要处理。类似的还有许多搜索图的算法,例如在垃圾回收阶段对堆进行标记,都可以通过工作密取机制来实现高效并行。当一个工作线程找到新的任务单元时,它会将其放到自己队列的末尾(或者在工作共享模式中,放入其它工作者线程的队列中)。当双端队列为空时,它会在另一个线程的队列末尾查找新的任务,从而确保每个线程都保持忙碌状态。
————————————————
版权声明:本文为CSDN博主「老马啸西风」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ryo1060732496/article/details/88889886

array和linked的比较

上面举出的LinkedBlockingQueue、ArrayBlockingQueue为例子,需求可以从很多方面去考虑:

  1. 考虑应用场景中对队列边界的要求。ArrayBlockingQueue是有明确的容量限制的,而LinkedBlockingQueue则取决于我们是否在创建时指定,SynchronousQueue则干脆不 能缓存任何元素。
  2. 从空间利用角度,数组结构的ArrayBlockingQueue要比LinkedBlockingQueue紧凑,因为其不需要创建所谓节点,但是其初始分配阶段就需要一段连续的空间,所以初始内存 需求更大。
  3. 通用场景中,LinkedBlockingQueue的吞吐量一般优于ArrayBlockingQueue,因为它实现了更加细粒度的锁操作。

ArrayBlockingQueue实现比较简单,性能更好预测,属于表现稳定的“选手”。
————————————————
版权声明:本文为CSDN博主「2NaCl」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_41936805/article/details/96307821