问题:
并发包中ConcurrentLinkedQueue和LinkedBlockingQueue有什么区别?
知识点
- Java并发类库中提供的各种各样的线程安全队列
- BlockingQueue提供了特定的等待性操作,获取(take)等待元素进队,或者插入(put)等待队列出现空位。
源码:
|
|
|
|
- ArrayBlockQueue是典型的有界队列,其内部是以final的数组保存数据,数组的大小就决定了队列的边界,所以我们在创建ArrayBlockingQueue时,都指定容量,如:
|
|
- LinkedBlockingQueue,容易被误解为无边界,但其行为和内部代码都是基于有界的逻辑实现的,只不过如果我们没有在创建队列时就指定容量,那么其容量限制就自动设置Integer.MAX_VALUE,称为了无界队列。
|
|
- SynchronousQueue,这是一个非常奇葩的队列实现,每个删除操作都要等待插入操作,反之每个插入操作都要等待删除动作。那么这个队列的容量是多少呢?是1吗?其实不是的,其内部容量是0。
- PriorityBlockingQueue是无边界的优先队列,虽然严格意义上讲,其大小总归是手系统资源影响。
- DelayQueue和LinkedTransferQueue同样是无边界的队列。对于无边界的队列,有一个自然的结果,就是put操作永远也不会发生其他BlockingQueue的那种等待情况。
回答问题:
有时候我们把并发包下面的所有容器都习惯叫做并发容器,但是严格来讲,类似ConcurrentLinkedQueue这种“Concurrent”容器,才是真正代表并发。
关于问题中它们的区别: - Concurrent类型基于lock-free,在常见的多线程访问场景,一般可以提供较高吞吐量。
- 而LinkedBlockingQueue内部则是基于锁,并提供了BlockingQueue的等待性方法。
不知道你有没有注意到,java.util.concurrent包提供的容器(Queue、List、Set)、Map,从命名上可以大概区分为Concurrent*、CopyOnWrite和Blocking等三类,同样是线程安全容器,可以简单认为: - Concurrent类型没有类似CopyOnWrite之类容器较重的修改开销。
- 但是,凡是都是有代价的,Concurrent往往提供了较低的遍历一致性,你可以这样理解所谓的弱一致性,例如,当李勇迭代器遍历时,如果容器发生修改,迭代器仍然可以继续进行遍历。
- 与弱一致性对应的,就是我介绍过的同步容器常见的行为“fail-fast”,也就是检测到容器在遍历过程中发生了修改,则抛出ConcurrentModificationException,不再继续遍历。
- 弱一致性的另外一个体现是,size等操作准确性是有线的,未必是100%准确。
- 与此同时,读取的性能具有一定的不确定性。
参考:
- 队列中部分源码
- 极客时间APP核心技术第20讲| 并发包中ConcurrentLinkedQueue和LinkedBlockingQueue有什么区别?
声明:此为原创,转载请联系作者
作者:微信公众号添加公众号-遛狗的程序员 ,或者可以扫描以下二维码关注相关技术文章。
当然喜爱技术,乐于分享的你也可以可以添加作者微信号: