JUC并发工具---阻塞队列

阻塞队列也就是BlockingQueue,它是一个接口,继承了Queue接口,是队列的一种。

使用阻塞队列的话,就不会发生线程安全问题,降低我们的开发的难度和工作量(不用我们自己考虑线程安全,而是转移到队列上),实现了隔离,提升了安全性。

主要并发队列关系图

[外链图片转存中…(img-7Uko6uLa-1734860138402)]

阻塞队列非阻塞队列Deque
ArrayBlockingQueueConcurrentLinkedQueue 用CAS保证了线程安全双端队列
LinkedBlockingQueue
SynchronousQueue
DelayQueue
PriorityBlockingQueue
LinkedTransferQueue

阻塞队列常用方法

add,remove,element

抛出异常

add():往队列里添加一个元素,如果队列满了,就会抛出异常来提示队列已满

remove():删除元素,如果我们删除的队列是空的,remove方法就会抛出异常

element():返回队列的头部节点但不删除,如果我们用这个方法去操作一个空队列,想获取队列的头结点,可是由于队列是空的,会抛出和前面remove方法一样的异常

offer,poll,peek

返回操作结果但不抛出异常

对应add(),remove(), element()方法

put,take

阻塞

put方法插入元素时:如果队列没有满,就和普通的插入一样是正常的插入,如果队列已满就无法继续插入,则阻塞,直到队列里有了空闲空间。如果后续队列有了空闲空间,队列就会解除阻塞状态,并把需要添加的数据添加到队列中

take 方法的功能:获取并移除队列的头结点,通常在队列里有数据的时候是可以正常移除的,可是一旦执行take方法的时候,队列里无数据,则阻塞,一旦队列里有数据就会立刻解除阻塞状态,并且取到数据

常见的阻塞队列

ArrayBlockingQueueLinkedBlockingQueeuSynchronousQueuePriorityBlockingQueueDelayQueue
有界,创建容量后不可扩容无界,默认容量是整数的最大值Integer.MAX_VALUE容量为0,所做的就是直接传递支持优先级的无界阻塞队列,后续可以扩容无界
内部使用数组存储元素内部使用链表实现可以通过初始化构造器参数Comparator来指定排序规则。插入的对象必须是可以Comparable的可以设定让队列中的任务延迟多久之后执行。
里面的元素必须实现Delayed接口
利用ReentrantLock实现线程安全次取数据都要先阻塞,直到有数据被放入,同理,每次放数据的时候也会阻塞,直到有消费者来取

阻塞和非阻塞队列的并发安全原理

[外链图片转存中…(img-Bu1eKWAi-1734860138402)]

[外链图片转存中…(img-kGcXpc58-1734860138402)]

如何选择

功能比如是否需要阻塞队列帮我们排序,如优先级排序、延迟执行等
如果有这个需要,我们就必须选择类似于PriorityBlockingQueue之类的有排序能力的阻塞队列
容量或者说是否有存储的要求,还是只需要“直接传递”
在考虑这一点的时候,我们知道前面介绍的那几种阻塞队列,有的是容量固定的
如ArrayBlockingQueue;有的默认是容量无限的,如LinkedBlockingQueue;而有的里面没有任何容
量,如 SynchronousQueue;而对于DelayQueue 而言,它的容量固定就是Integer.MAX_VALUE
所以不同阻塞队列的容量是千差万别的,我们需要根据任务数量来推算出合适的容量,从而去选取合适
的 BlockingQueue
能否扩容因为有时我们并不能在初始的时候很好的准确估计队列的大小,因为业务可能有高峰期、低谷期如果一开
始就固定一个容量,可能无法应对所有的情况,也是不合适的,有可能需要动态扩容
如果我们需要动态扩容的话,那么就不能选择ArrayBlockingQueue,因为它的容量在创建时就确定了,
无法扩容
相反,PriorityBlockingQueue即使在指定了初始容量之后,后续如果有需要,也可以自动扩容所以我们
可以根据是否需要扩容来选取合适的队列
内存结构在上一课时我们分析过ArrayBlockingQueue的源码,看到了它的内部结构是“数组”的形式
和它不同的是,LinkedBlockingQueue的内部是用链表实现的
所以这里就需要我们考虑到,ArrayBlockingQueue没有链表所需要的“节点”,空间利用率更高
所以如果我们对性能有要求可以从内存的结构角度去考虑这个问题
性能比如LinkedBlockingQueue由于拥有两把锁,它的操作粒度更细,在并发程度高的时候,相对于只有
一把锁的ArrayBlockingQueue性能会更好
另外,SynchronousQueue性能往往优于其他实现,因为它只需要“直接传递”,而不需要存储的过
程。如果我们的场景需要直接传递的话,可以优先考虑SynchronousQueue
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bufanjun001

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值