ConcurrentLinkedQueue的探究之路

本文探讨了ConcurrentLinkedQueue,一个基于无锁算法的并发队列。它利用CAS和自旋实现线程安全,避免使用锁。ConcurrentLinkedQueue内部结构为单链表,通过自旋和CAS保证并发操作的正确性。队列的迭代器是弱一致性的,不保证实时数据一致性。文章还分析了入队和出队的源码实现,指出tail节点不一定是最后一个节点,通过减少对volatile变量的写操作提高效率。此外,文章讨论了ConcurrentLinkedQueue在多线程环境中的应用场景和与阻塞队列的比较。
摘要由CSDN通过智能技术生成

参考及引用声明:

Java多线程进阶(二九)—— J.U.C之collections框架:ConcurrentLinkedQueue

(推荐)Java并发编程之ConcurrentLinkedQueue详解

并发容器-ConcurrentLinkedQueue详解

 

,我们要知道ConcurrentLinkedQueue是个啥?

在并发编程中,一般需要用到安全的队列,如果要自己实现安全队列,可以使用2种方式:

  • 方式1:加锁,这种实现方式就是我们常说的阻塞队列。(如 BlockingLinkedQueue)
  • 方式2:使用循环CAS算法实现,这种方式实现队列称之为非阻塞队列。(如 ConcurrentLinkedQueue

ConcurrentLinkedQueue是JDK1.5时随着J.U.C一起引入的一个支持并发环境的基于链表实现的队列。(基于链接节点的无界线程安全的队列,按照先进先出原则对元素进行排序。新元素从队列尾部插入,而获取队列元素,则需要从队列头部获取。)

二,CLQ是如何实现“安全”的?

没有利用锁或底层同步原语(无锁算法),而是完全基于自旋+CAS的方式实现了该队列。

扩展:CAS和自旋

来源:

https://blog.csdn.net/weixin_44594056/article/details/90552443

https://blog.csdn.net/qq_36071795/article/details/83818320

CAS:CAS(Compare And Swap/Set)比较并交换,CAS 算法的过程是这样:它包含 3 个参数 CAS(V,E,N)。V 表示要更新的变量(内存值),E 表示预期值(旧的),N 表示新值。当且仅当 V 值等于 E 值时,才会将 V 的值设为 N,如果 V 值和 E 值不同,则说明已经有其他线程做了更新,则当前线程什么都不做。最后,CAS 返回当前 V 的真实值。

CAS 操作是抱着乐观的态度进行的(乐观锁),它总是认为自己可以成功完成操作。当多个线程同时使用 CAS 操作一个变量时,只有一个会胜出,并成功更新,其余均会失败。失败的线程不会被挂起,仅是被告知失败,并且允许再次尝试,当然也允许失败的线程放弃操作。(ABA问题--通过版本号解决)

自旋:就是指当有另外一个线程来竞争锁时,这个线程会在原地循环等待,而不是把该线程给阻塞,直到那个获得锁的线程释放锁之后,这个线程就可以马上获得锁的。锁在原地循环的时候,是会消耗cpu的,就相当于在执行一个啥也没有的for循环。基于这个问题,我们必须给线程空循环设置一个次数,当线程超过了这个次数,我们就认为,继续使用自旋锁就不适合了,此时锁会再次膨胀,升级为重量级锁。

(自适应自旋锁:线程空循环等待的自旋次数并非是固定的,而是会动态着根据实际情况来改变自旋等待的次数)

好,我们继续回来扒这个ConcurrentLinkedQueue。

由于是完全基于无锁算法实现的,所以当出现多个线程同时进行修改队列的操作(比如同时入队),很可能出现CAS修改失败的情况,那么失败的线程会进入下一次自旋,再尝试入队操作,直到成功。所以,在并发量适中的情况下,ConcurrentLinkedQueue一般具有较好的性能。

ConcurrentLinkedQueue内部就是一个简单的单链表结构,每入队一个元素就是插入一个Node类型的结点。字段head指向队列头,tail指向队列尾,通过Unsafe来CAS操作字段值以及Node对象的字段值。

clipboard.png

由于队列本身是一种链表结构,所以虽然算法看起来很简单,但其实需要考虑各种并发的情况,实现复杂度较高,并且ConcurrentLinkedQueue不具备实时的数据一致性,实际运用中,队列一般在生产者-消费者的场景下使用得较多,所以ConcurrentLinkedQueue的使用场景并不如阻塞队列那么多。

扩展:Unsafe类

来源:https://www.jianshu.com/p/2e5b92d0962e

  • Java 不能直接访问操作系统底层,而是通过本地方法来访问。Unsafe 类提供了硬件级别的原子操作。
  • Unsafe无法实例化(构造方法私有)&#x
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值