ConcurrentLinkedQueue和BlockingQueue的审核与复核区别在哪里到底在哪里

问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
当用LinkedBlockingQueue的take()方法获取队列信息时
一旦队列为空,则进入阻塞状态
再往队列里put()元素,take()方法会自动获取新加入元素,还是始终保持阻塞状态?
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
自动获取,不会阻塞了
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
如果还是阻塞,这个类还有什么用?
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
建议看看源码,就知道了,很有好处的
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
你采纳的答案是错误的。ConcurrentLinkedQueue是不阻塞的,LinkedBlockingQueue是阻塞的。分别给你上代码:如下:
import java.util.concurrent.LinkedBlockingQ
public class TestLinkedBlockingQueue {
public static void main(String[] args) {
LinkedBlockingQueue&String& queue = new LinkedBlockingQueue&String&();
queue.put("a");
queue.put("b");
System.out.println(queue.take());
System.out.println(queue.take());
System.out.println(queue.take());
queue.put("c");
System.out.println(queue.take());
} catch (InterruptedException e) {
e.printStackTrace();
//输出结果:
但是你再看非阻塞的ConcurrentLinkedQueue
import java.util.concurrent.ConcurrentLinkedQ
public class TestConcurrentLinkedQueue {
public static void main(String[] args) {
ConcurrentLinkedQueue&String& queue = new ConcurrentLinkedQueue&String&();
queue.add("a");
queue.add("b");
System.out.println(queue.peek());
queue.remove();
System.out.println(queue.peek());
queue.remove();
System.out.println(queue.peek());
queue.remove();
queue.add("c");
System.out.println(queue.peek());
queue.remove();
//Exception in thread "main" java.util.NoSuchElementException
at java.util.AbstractQueue.remove(AbstractQueue.java:117)
at TestConcurrentLinkedQueue.main(TestConcurrentLinkedQueue.java:14)
同步到新浪微博
分享到微博?
你好!看起来你挺喜欢这个内容,但是你还没有注册帐号。 当你创建了帐号,我们能准确地追踪你关注的问题,在有新答案或内容的时候收到网页和邮件通知。还能直接向作者咨询更多细节。如果上面的内容有帮助,记得点赞 (????)? 表示感谢。
明天提醒我
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:后使用快捷导航没有帐号?
查看: 647|回复: 7
并发队列ConcurrentLinkedQueue与阻塞队列LinkedBlockingQueue的区别
中级会员, 积分 237, 距离下一级还需 263 积分
论坛徽章:14
中级会员, 积分 328, 距离下一级还需 172 积分
论坛徽章:2
ConcurrentLinkedQueue采用CAS乐观锁 LinkedBlockingQueue采用传统悲观锁 理论上来说性能应该是前者高
中级会员, 积分 279, 距离下一级还需 221 积分
论坛徽章:8
ConcurrentLinkedQueue竞争失败后只是去不断重试,理论上相比起BlockingQueue一次线程的挂起和恢复的时钟周期花销的小的多。 另一个是BlockingQueue中只能有一个线程处于工作状态,而ConcurrentLinkedQueue读写可以并行
中级会员, 积分 317, 距离下一级还需 183 积分
论坛徽章:4
感谢楼主好心分享!!!
金牌会员, 积分 2336, 距离下一级还需 664 积分
论坛徽章:17
是自己写的吗?较好能够自己总结
注册会员, 积分 59, 距离下一级还需 141 积分
论坛徽章:2
感谢分享,要是能把帖子的内容搬过来就更好了~
论坛徽章:38
感谢楼主好心分享!!!
中级会员, 积分 458, 距离下一级还需 42 积分
论坛徽章:8
感谢楼主好心分享!!!
扫一扫加入本版微信群\ java并发面试常识之LinkedBlockingQueue
java并发面试常识之LinkedBlockingQueue
这位童鞋很懒,什么也没有留下~~!
谈到ArrayBlockingQueue的特色就是循环队列,然后一把锁,2个条件,完成了功能。本来以为LinkedBlockingQueue也是这样的,结果和预期不一样,LinkedBlockingQueue利用了链表的特点,使用了两把锁,两个条件来控制。是一个锁分离的应用,下面就说说,他的实现,以及为什么ArrayBlockingQueue就不适合锁分离。
主要成员变量
private final ReentrantLock takeLock = new ReentrantLock();
private final Condition notEmpty = takeLock.newCondition();
private final ReentrantLock putLock = new ReentrantLock();
private final Condition notFull = putLock.newCondition();
private final AtomicInteger count = new AtomicInteger();
除了两个锁,两个条件外,我这里专门列举了计数器。这个计数器很重要,重要到锁分离要依赖他才能正常运行。
使用双锁分离就得注意一点,那就是防止线程夯死。生产线程要唤醒生产线程,消费线程也要唤醒生产线程,消费线程唤醒消费线程,消费线程也要唤醒生产线程。
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
//唤醒标记
int c = -1;
Node&E& node = new Node&E&(e);
final ReentrantLock putLock = this.putL
final AtomicInteger count = this.
putLock.lockInterruptibly();
while (count.get() == capacity) {
//阻塞生产线程
notFull.await();
enqueue(node);
c = count.getAndIncrement();
if (c + 1 & capacity)
//唤醒生产线程
notFull.signal();
} finally {
putLock.unlock();
//唤醒消费线程
if (c == 0)
signalNotEmpty();
生产线程唤醒消费线程
基于上面的介绍,我们来看代码,唤醒标记就是为了生产唤醒消费的,因为可能出现消费线程全部都已经等待了,此时生产线程运作,但是消费线程并不能自己唤醒自己,于是就有了signalNotEmpty()的操作。这里的c是getAndIncrement的值,就是获取计数之前的值。c==0的满足条件就有1个元素,在这种情况下才去唤醒消费线程。
生产线程唤醒生产线程
在获取锁后,如果发现容量达到上限,就阻塞了,等待被唤醒,如果可以加入,就执行enqueue方法,是个很简单的链表添加节点的方法。就是在原来last节点后加节点,然后更新last节点。
private void enqueue(Node&E& node) {
last = last.next =
在计数器自增后,判断唤醒标记,如果还能继续生产,就去唤醒生产线程。
消费的方案思想和生产类似,这里就不说代码了。
public boolean remove(Object o) {
if (o == null)
fullyLock();
for (Node&E& trail = head, p = trail.
trail = p, p = p.next) {
if (o.equals(p.item)) {
unlink(p, trail);
} finally {
fullyUnlock();
删除代码相对比较简单,主要是要获取两把锁,才能进行删除操作就是fullyLock()和fullyUnlock(),删除掉元素后,还要唤醒生产线程。
void unlink(Node&E& p, Node&E& trail) {
trail.next = p.
if (last == p)
if (count.getAndDecrement() == capacity)
notFull.signal();
ArrayBlockingQueue为何不适合锁分离
这个主要是循环队列的原因,主要是数组和链表不同,链表队列的添加和头部的删除,都是只和一个节点相关,添加只往后加就可以,删除只从头部去掉就好。为了防止head和tail相互影响出现问题,这里就需要原子性的计数器,头部要移除,首先得看计数器是否大于0,每个添加操作,都是先加入队列,然后计数器加1,这样保证了,队列在移除的时候,长度是大于等于计数器的,通过原子性的计数器,双锁才能互不干扰。数组的一个问题就是位置的选择没有办法原子化,因为位置会循环,走到最后一个位置后就返回到第一个位置,这样的操作无法原子化,所以只能是加锁来解决。
LinkedBlockingQueue的优点是锁分离,那就很适合生产和消费频率差不多的场景,这样生产和消费互不干涉的执行,能达到不错的效率,尽量不使用remove操作,获取两把锁的效率更低,可以使用size方法(就是计数器直接返回),这个还是比较重要的,有些集合不适合使用size,例如ConcurrentLinkedQueue,正确应该使用isEmpty()。
相关标签:
请登录后,发表评论
评论(Enter+Ctrl)
评论加载中...
评论加载中...
Copyright (C)
All Rights Reserved | 京ICP备 号-2并发队列ConcurrentLinkedQueue、阻塞队列AraayBlockingQueue、阻塞队列LinkedBlockingQueue 区别 和& 使用场景总结
三者区别与联系: 联系,三者 都是线程安全的。区别,就是 并发& 和 阻塞,前者为并发队列,因为采用cas算法,所以能够高并发的处理;后2者采用锁机制,所以是阻塞的。注意点就是前者由于采用cas算法,虽然能高并发,但cas的特点造成操作的危险性,怎么危险性可以去查一下cas算法(但一些多消费性的队列还是用的它,原因看下边使用场景中的说明)
后2者区别:联系,第2和第3都是阻塞队列,都是采用锁,都有阻塞容器Condition,通过Condition阻塞容量为空时的取操作和容量满时的写操作第。区别,第2就一个整锁,第3是2个锁,所以第2第3的锁机制不一样,第3比第2吞吐量 大,并发性能也比第2高。
后2者的具体信息:&& LinkedBlockingQueue是BlockingQueue的一种使用Link List的实现,它对头和尾(取和添加操作)采用两把不同的锁,相对于ArrayBlockingQueue提高了吞吐量。它也是一种阻塞型的容器,适合于实现&消费者生产者&模式。
ArrayBlockingQueue是对BlockingQueue的一个数组实现,它使用一把全局的锁并行对queue的读写操作,同时使用两个Condition阻塞容量为空时的取操作和容量满时的写操作。
&正因为LinkedBlockingQueue使用两个独立的锁控制数据同步,所以可以使存取两种操作并行执行,从而提高并发效率。而ArrayBlockingQueue使用一把锁,造成在存取两种操作争抢一把锁,而使得性能相对低下。LinkedBlockingQueue可以不设置队列容量,默认为Integer.MAX_VALUE.其容易造成内存溢出,一般要设置其值。
使用场景总结:
适用阻塞队列的好处:多线程操作共同的队列时不需要额外的同步,另外就是队列会自动平衡负载,即那边(生产与消费两边)处理快了就会被阻塞掉,从而减少两边的处理速度差距,自动平衡负载这个特性就造成它能被用于多生产者队列,因为你生成多了(队列满了)你就要阻塞等着,直到消费者消费使队列不满你才可以继续生产。 当许多线程共享访问一个公共&collection&时,ConcurrentLinkedQueue&是一个恰当的选择。
LinkedBlockingQueue 多用于任务队列(单线程发布任务,任务满了就停止等待阻塞,当任务被完成消费少了又开始负载 发布任务)
ConcurrentLinkedQueue &多用于消息队列(多个线程发送消息,先随便发来,不计并发的-cas特点)
多个生产者,对于LBQ性能还算可以接受;但是多个消费者就不行了mainLoop需要一个timeout的机制,否则空转,cpu会飙升的。LBQ正好提供了timeout的接口,更方便使用 如果CLQ,那么我需要收到处理sleep
单生产者,单消费者 &用&LinkedBlockingqueue&&
多生产者,单消费者 &&用&LinkedBlockingqueue&&
单生产者 ,多消费者 &&用&ConcurrentLinkedQueue
多生产者 ,多消费者 &&用&ConcurrentLinkedQueue
对上边总结:
如消息队列,好多client发来消息,根据client发送先后放入队列中,先发送的就先放进来,然后由于队列是先进先出,是一个一个出来的,所以不涉及到线程安全问题,所以用LinkedBlockingqueue&&队列。比如还拿上边消息队列那个例子,由于队列是一个一个出来的,出来一个消息协议体就由线程池分配一个线程去处理这个消息体,这个消息体对于线程池来说谈不上共享不共享的问题,即不会多个线程去抢同一个消息体去执行,所以就不需要用线程安全的队列结构了;那假如一种情况,队列里仍然是一个一个的出来,但是出来的这个元素是 线程池共享的,即大家线程都需要用到这个从队列里出来的这个元素,也就是多消费者消费同一个东西这种情况,所以就要用线程安全的队列了,即ConcurrentLinkedQueue。
阅读(...) 评论()1062人阅读
并发编程(13)
在Java多线程应用中,队列的使用率很高,多数生产消费模型的首选数据结构就是队列(先进先出)。Java提供的线程安全的Queue可以分为阻塞队列和非阻塞队列,其中阻塞队列的典型例子是BlockingQueue,非阻塞队列的典型例子是ConcurrentLinkedQueue,在实际应用中要根据实际需要选用阻塞队列或者非阻塞队列。
注:什么叫线程安全?这个首先要明确。线程安全就是说多线程访问同一代码,不会产生不确定的结果。
并行和并发区别
1、并行是指两者同时执行一件事,比如赛跑,两个人都在不停的往前跑;
2、并发是指资源有限的情况下,两者交替轮流使用资源,比如一段路(单核CPU资源)同时只能过一个人,A走一段后,让给B,B用完继续给A ,交替使用,目的是提高效率
LinkedBlockingQueue
由于LinkedBlockingQueue实现是线程安全的,实现了先进先出等特性,是作为生产者消费者的首选,LinkedBlockingQueue 可以指定容量,也可以不指定,不指定的话,默认最大是Integer.MAX_VALUE,其中主要用到put和take方法,put方法在队列满的时候会阻塞直到有队列成员被消费,take方法在队列空的时候会阻塞,直到有队列成员被放进来。
package cn.
import java.util.concurrent.BlockingQ
import java.util.concurrent.ExecutorS
import java.util.concurrent.E
import java.util.concurrent.LinkedBlockingQ
* 多线程模拟实现生产者/消费者模型
* @author tkhoon
public class BlockingQueueTest2 {
* 定义装苹果的篮子
public class Basket {
// 篮子,能够容纳3个苹果
BlockingQueue&String& basket = new LinkedBlockingQueue&String&(3);
// 生产苹果,放入篮子
public void produce() throws InterruptedException {
// put方法放入一个苹果,若basket满了,等到basket有位置
basket.put(&An apple&);
// 消费苹果,从篮子中取走
public String consume() throws InterruptedException {
// take方法取出一个苹果,若basket为空,等到basket有苹果为止(获取并移除此队列的头部)
return basket.take();
// 定义苹果生产者
class Producer implements Runnable {
public Producer(String instance, Basket basket) {
this.instance =
this.basket =
public void run() {
while (true) {
// 生产苹果
System.out.println(&生产者准备生产苹果:& + instance);
basket.produce();
System.out.println(&!生产者生产苹果完毕:& + instance);
// 休眠300ms
Thread.sleep(300);
} catch (InterruptedException ex) {
System.out.println(&Producer Interrupted&);
// 定义苹果消费者
class Consumer implements Runnable {
public Consumer(String instance, Basket basket) {
this.instance =
this.basket =
public void run() {
while (true) {
// 消费苹果
System.out.println(&消费者准备消费苹果:& + instance);
System.out.println(basket.consume());
System.out.println(&!消费者消费苹果完毕:& + instance);
// 休眠1000ms
Thread.sleep(1000);
} catch (InterruptedException ex) {
System.out.println(&Consumer Interrupted&);
public static void main(String[] args) {
BlockingQueueTest2 test = new BlockingQueueTest2();
// 建立一个装苹果的篮子
Basket basket = test.new Basket();
ExecutorService service = Executors.newCachedThreadPool();
Producer producer = test.new Producer(&生产者001&, basket);
Producer producer2 = test.new Producer(&生产者002&, basket);
Consumer consumer = test.new Consumer(&消费者001&, basket);
service.submit(producer);
service.submit(producer2);
service.submit(consumer);
// 程序运行5s后,所有任务停止
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
e.printStackTrace();
service.shutdownNow();
ConcurrentLinkedQueue
ConcurrentLinkedQueue是Queue的一个安全实现.Queue中元素按FIFO原则进行排序.采用CAS操作,来保证元素的一致性。
LinkedBlockingQueue是一个线程安全的阻塞队列,它实现了BlockingQueue接口,BlockingQueue接口继承自java.util.Queue接口,并在这个接口的基础上增加了take和put方法,这两个方法正是队列操作的阻塞版本。
package cn.
import java.util.concurrent.ConcurrentLinkedQ
import java.util.concurrent.CountDownL
import java.util.concurrent.ExecutorS
import java.util.concurrent.E
public class ConcurrentLinkedQueueTest {
private static ConcurrentLinkedQueue&Integer& queue = new ConcurrentLinkedQueue&Integer&();
private static int count = 2; // 线程个数
//CountDownLatch,一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
private static CountDownLatch latch = new CountDownLatch(count);
public static void main(String[] args) throws InterruptedException {
long timeStart = System.currentTimeMillis();
ExecutorService es = Executors.newFixedThreadPool(4);
ConcurrentLinkedQueueTest.offer();
for (int i = 0; i & i++) {
es.submit(new Poll());
latch.await(); //使得主线程(main)阻塞直到latch.countDown()为零才继续执行
System.out.println(&cost time & + (System.currentTimeMillis() - timeStart) + &ms&);
es.shutdown();
public static void offer() {
for (int i = 0; i & 100000; i++) {
queue.offer(i);
* @author tkhoon
static class Poll implements Runnable {
public void run() {
// while (queue.size()&0) {
while (!queue.isEmpty()) {
System.out.println(queue.poll());
latch.countDown();
运行结果:
costtime 2360ms
改用while (queue.size()&0)后
运行结果:
cost time 46422ms
结果居然相差那么大,看了下ConcurrentLinkedQueue的API原来.size()是要遍历一遍集合的,难怪那么慢,所以尽量要避免用size而改用isEmpty().
总结了下, 在单位缺乏性能测试下,对自己的编程要求更加要严格,特别是在生产环境下更是要小心谨慎。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:73178次
积分:1247
积分:1247
排名:千里之外
原创:45篇
评论:10条
(window.slotbydup = window.slotbydup || []).push({
id: '4740881',
container: s,
size: '200,200',
display: 'inlay-fix'}

我要回帖

更多关于 奥迪plus区别在哪里 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信