ConcurrentLinkedQueue基于JDK1.8源码学习心得
Posted taozi1115402474
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ConcurrentLinkedQueue基于JDK1.8源码学习心得相关的知识,希望对你有一定的参考价值。
最近在读《Java并发编程的艺术》,书中关于ConcurrentLinkedQueue的描述并不是基于JDK1.8
相较于JDK1.8版本的,还是修改了挺多地方的,比如关于HOPS的设计意图直接去掉了
参考贴:https://www.jianshu.com/p/08e8b0c424c0
https://blog.csdn.net/lejustdoit/article/details/98477819?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase
大部分东西上面两篇博客已经讲的很清楚了,这里补充一点自己的学习时候没清楚的点
1 public boolean offer(E e) { 2 checkNotNull(e); 3 final Node<E> newNode = new Node<E>(e); 4 5 for (Node<E> t = tail, p = t;;) { 6 Node<E> q = p.next; 7 if (q == null) { 8 if (p.casNext(null, newNode)) { 9 if (p != t) 10 casTail(t, newNode); 11 return true; 12 }//1CAS自旋失败 13 } 14 else if (p == q)//2某个线程提前出队节点导致p=q,详情见第一篇参考贴 15 p = (t != (t = tail)) ? t : head; 16 else//3让p指针始终指向尾节点 17 p = (p != t && t != (t = tail)) ? t : q; 18 } 19 }
1、注解1,2,3都是当前节点插入失效,需要重新插入,2考虑了tail滞后于head的情况(节点出队,详情见第一篇参考贴)
注解3和4中的t=tail这步操作很神奇,它有效的减少了CAS更新tail节点的次数,这也是曾经的HOPS的设计意图
t=tail跟CAS相比有线程安全问题,但是这里对线程安全的要求并不高,因为判断是否真的是尾节点在if (q == null),所以它只是象征性的更新一下尾节点
若刚好更新成为尾节点,那么CAS更新casTail(t, newNode)这步不就不用做了
若运气不好没有更新尾节点,那么并不影响下次循环
2、p = (t != (t = tail)) ? t : head;
这里比较的是地址是否相同,而不是值
刚开始以为一直是true,先执行t=tail,然后判断t!=t,debug的时候发现不是
首先判断t的地址是否是tail,然后才是t=taill,测试代码如下
1 class No { 2 int k, v; 3 public No(int k, int v) { 4 this.k = k; 5 this.v = v; 6 } 7 } 8 No B = new No(3, 4); 9 No A = B;//当A=B时返回1 2 10 //No A = new No(1, 9);//当A!=B时返回3 4 11 No C = new No(1, 2); 12 No D = (A!=(A=B))?A:C; 13 System.out.println(D.k + " " + D.v);
然后还有一句这个,p = (p != t && t != (t = tail)) ? t : q;
根据&&的特性,如果p=t那么&&后的语句将不会被执行,也就是说t最后没有被赋值
3、可以发现程序当前已经经过casNext方法,可以发现此时p指针并没有指向新节点newNode
以上是关于ConcurrentLinkedQueue基于JDK1.8源码学习心得的主要内容,如果未能解决你的问题,请参考以下文章