LinkedBlockingQueue 和 ConcurrentLinkedQueue的区别
1. 简单的开篇
LinkedBlockingQueue 和 ConcurrentLinkedQueue 是 Java 高并发场景中最常使用的队列。尽管这两个队列经常被用作并发场景的数据结构,但它们之间仍有细微的特征和行为差异。
在这篇文章中,我将和大家一起探讨这两者之间的异同点。欢迎大家在留言讨论~
2. LinkedBlockingQueue
首先 LinkedBlockingQueue 是一个 “可选且有界” 的阻塞队列实现,你可以根据需要指定队列的大小。
接下来,我将创建一个LinkedBlockingQueue,它最多可以包含100个元素:
BlockingQueue<Integer> boundedQueue = new LinkedBlockingQueue<>(100);
当然,我们也可以通过不指定大小,来创建一个无界的 LinkedBlockingQueue:
BlockingQueue<Integer> unboundedQueue = new LinkedBlockingQueue<>();
无界队列表示在创建时未指定队列的大小。因此,队列可以随着元素的添加而动态增长。但是,如果没有剩余内存,则队列将抛出 java.lang.OutOfMemory 错误。
这里留下一个问题给大家思考: 创建无界队列是好还是坏呢?
我们还可以从现有的集合来创建 LinkedBlockingQueue:
Collection<Integer> listOfNumbers = Arrays.asList(1,2,3,4,5);
BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(listOfNumbers);
LinkedBlockingQueue 实现了BlockingQueue接口,该接口为它提供了阻塞性质。
阻塞队列表示如果访问线程已满(当队列有界时)或变为空,则队列将阻塞该线程。如果队列已满,则添加新元素将阻塞访问线程,除非新元素有可用空间。类似地,如果队列为空,则访问元素会阻塞调用线程:
ExecutorService executorService = Executors.newFixedThreadPool(1);
LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>();
executorService.submit(() -> {
try {
queue.take();
}
catch (InterruptedException e) {
// exception handling
}
});
在上面的代码片段中,我们正在访问一个空队列。因此,take() 方法阻塞调用线程。
LinkedBlockingQueue 的阻塞特性与一些开销相关。这个代价是因为每个put或take操作在生产者线程或使用者线程之间都是锁争用的。因此,在许多生产者和消费者的情况下,put和take 动作可能会慢一些。
3. ConcurrentLinkedQueue
首先声明,ConcurrentLinkedQueue 是一个无边界、线程安全且无阻塞的队列
创建一个空的 ConcurrentLinkedQueue:
ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue();
同上面一样,我们也可以从现有集合创建 ConcurrentLinkedQueue:
Collection<Integer> listOfNumbers = Arrays.asList(1,2,3,4,5);
ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<>(listOfNumbers);
不同于 LinkedBlockingQueue, ConcurrentLinkedQueue是非阻塞的队列。因此,即使队列为空(empty),它也不会阻塞线程。相反,它会返回 空(null) 。虽然它是无界的,但如果没有额外的内存来添加新元素,它依旧会抛出 java.lang.OutOfMemory 错误。
除了非阻塞之外,ConcurrentLinkedQueue还有其他特性。
在任何生产者-消费者场景中,消费者都不会满足于生产者;但是,多个生产者将相互竞争:
int element = 1;
ExecutorService executorService = Executors.newFixedThreadPool(2);
ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<>();
Runnable offerTask = () -> queue.offer(element);
Callable<Integer> pollTask = () -> {
while (queue.peek() != null) {
return queue.poll().intValue();
}
return null;
};
executorService.submit(offerTask);
Future<Integer> returnedElement = executorService.submit(pollTask);
assertThat(returnedElement.get().intValue(), is(equalTo(element)));
第一个任务 offerTask 向队列中添加元素,第二个任务 pollTask 从队列中检索元素。pollTask 首先检查队列中的元素,因为ConcurrentLinkedQueue是非阻塞的,并且可以返回null值。
4. 求同
LinkedBlockingQueue 和 ConcurrentLinkedQueue 都是队列实现,并具有一些共同特征。让我们讨论一下这两个队列的相似之处:
- 都 实现 Queue 接口
- 它们都使用 linked nodes 存储节点
- 都适用于并发访问场景
5. 存异
尽管这两种队列都有某些相似之处,但也有一些实质性的特征差异:
| 特性 | LinkedBlockingQueue | ConcurrentLinkedQueue |
|---|---|---|
| 阻塞性 | 阻塞队列,并实现blocking queue接口 | 非阻塞队列,不实现blocking queue接口 |
| 队列大小 | 可选的有界队列,这意味着可以在创建期间定义队列大小 | 无边界队列,并且没有在创建期间指定队列大小的规定 |
| 锁特性 | 基于锁的队列 | 无锁队列 |
| 算法 | 锁的实现基于 “双锁队列(two lock queue)” 算法 | 依赖于Michael&Scott算法来实现无阻塞、无锁队列 |
| 实现 | 在 双锁队列 算法机制中,LinkedBlockingQueue使用两种不同的锁,putLock和takeLock。put/take操作使用第一个锁类型,take/poll操作使用另一个锁类型 | 使用CAS(Compare And Swap)进行操作 |
| 阻塞行为 | 当队列为空时,它会阻塞访问线程 | 当队列为空时返回 null,它不会阻塞访问线程 |
6. 总结才能进步
首先,我们分别讨论了这两种队列实现及其一些特性、相似性、以及它们之间的差异。这样的比较,是否让你对这两种队列有了更深刻的印象?
公众号: 锅外的大佬 ,欢迎加群~
博客地址: http://www.developlee.top
LinkedBlockingQueue 和 ConcurrentLinkedQueue的区别的更多相关文章
- java LinkedBlockingQueue和ConcurrentLinkedQueue的区别
实现上看,两者都继承于AbstractQueue,但是ConcurrentLinkedQueue实现了Queue,而LinkedBlockingQueue实现了BlockingQueue,Blocki ...
- (原创)JAVA阻塞队列LinkedBlockingQueue 以及非阻塞队列ConcurrentLinkedQueue 的区别
阻塞队列:线程安全 按 FIFO(先进先出)排序元素.队列的头部 是在队列中时间最长的元素.队列的尾部 是在队列中时间最短的元素.新元素插入到队列的尾部,并且队列检索操作会获得位于队列头部的元素.链接 ...
- LinkedBlockingQueue和ConcurrentLinkedQueue详细用法
1.LinkedBlockingQueue<E>:java.util.concurrent API中的解释: public class LinkedBlockingQueue<E&g ...
- LinkedBlockingQueue 与ConcurrentLinkedQueue队列的不同与同
LinkedBlockingQueue 的API中,从队列中获取元素,有以下几个方法: 1.take():原文:Retrieves and removes the head of this queue ...
- Java并发编程原理与实战三十五:并发容器ConcurrentLinkedQueue原理与使用
一.简介 一个基于链接节点的无界线程安全队列.此队列按照 FIFO(先进先出)原则对元素进行排序.队列的头部 是队列中时间最长的元素.队列的尾部 是队列中时间最短的元素.新的元素插入到队列的尾部,队列 ...
- Java同步数据结构之ConcurrentLinkedQueue
前言 前面介绍的Queue都是通过Lock锁实现的阻塞队列,今天介绍一种非阻塞队列ConcurrentLinkedQueue,所谓非阻塞,其实就是通过CAS代替加锁来实现的高效的非阻塞队列.当许多线程 ...
- JUC源码分析-集合篇(六)LinkedBlockingQueue
JUC源码分析-集合篇(六)LinkedBlockingQueue 1. 数据结构 LinkedBlockingQueue 和 ConcurrentLinkedQueue 一样都是由 head 节点和 ...
- java.util.concurrent包下集合类的特点与适用场景
java.util.concurrent包,此包下的集合都不允许添加null元素 序号 接口 类 特性 适用场景 1 Queue.Collection ArrayBlockingQueue 有界.阻塞 ...
- Java多线程(六) —— 线程并发库之并发容器
参考文献: http://www.blogjava.net/xylz/archive/2010/07/19/326527.html 一.ConcurrentMap API 从这一节开始正式进入并发容器 ...
随机推荐
- python-多任务编程01-线程(threading)
并发:指的是任务数多余cpu核数,通过操作系统的各种任务调度算法,实现用多个任务“一起”执行(实际上总有一些任务不在执行,因为切换任务的速度相当快,看上去一起执行而已) 并行:指的是任务数小于等于cp ...
- mybatis连接池
连接池 在 Mybatis 中,数据源 dataSource 共有三类,分别是: UNPOOLED : 不使用连接池的数据源.采用传统的 javax.sql.DataSource 规范中的连接池,My ...
- .NET Core 发布到 IIS
①右键项目->属性 将生成配置为Release ②右键项目->重新生成 ③提示生成成功后,右键项目->发布 点击新建,-> 这一步可以选择文件系统, 也可以选择IIS FT 以 ...
- 痞子衡嵌入式:恩智浦i.MX RTxxx系列MCU特性那些事(1)- 概览
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是恩智浦i.MX RTxxx系列MCU的基本特性. 恩智浦半导体于2017年开始推出的i.MX RT系列重新定义了MCU,其第一款芯片i. ...
- 详解Java的对象创建
1. 前言 在<还不清楚怎样面向对象?>和<面向对象再探究>两篇文章中,都介绍了关于面向对象程序设计的概念和特点.其中也涉及到了许多代码,比如: Dog dog = new D ...
- Django学习路31_使用 locals 简化 context 写法,点击班级显示该班学生信息
urls 中 进行注册 url(r'grades',views.grades) views 中编写函数 def grades(request): grades_list = Grade.objects ...
- PHP flock() 函数
定义和用法 flock() 函数锁定或释放文件. 如果成功,该函数返回 TRUE.如果失败,则返回 FALSE. 语法 flock(file,lock,block) 参数 描述 file 必需.规定要 ...
- bzoj 4238 电压
LINK:电压 一张图 每个点可以为黑点或百点 每一条边的两端都必须为一黑一白.询问又多少条边满足除了这条边不满足条件其余所有边都满足条件. 分析一下这个所谓的条件 每一条边的两端必须为一黑一白 所以 ...
- luoguP2154 [SDOI2009]虔诚的墓主人
SDOI2009虔诚的墓主人 喜闻乐见,我终于把此题读懂了..所以可以写了. 其实就是让我们求有多少个十字架 一个十字架的定义为中间有一个空地 周围4个正方向都有k棵树. 不难想到nm的暴力 我们预处 ...
- 问题记录,php webserver端跨子域setcookie后浏览器不存
如题. path已设置成/,domain也已指定成父级域名,数据包response中可见Set-Cookie header为期望的cookie数据,但浏览器就是不接收.存储该cookie, 浏览器端也 ...