* In addition to using deletion markers, the lists also use * nullness of value fields to indicate deletion, in a style * similar to typical lazy-deletion schemes. If a node's value is * null, then it is considered logically deleted and ignored even * though it is still reachable. This maintains proper control of * concurrent replace vs delete operations -- an attempted replace * must fail if a delete beat it by nulling field, and a delete * must return the last non-null value held in the field. (Note: * Null, rather than some special marker, is used for value fields * here because it just so happens to mesh with the Map API * requirement that method get returns null if there is no * mapping, which allows nodes to remain concurrently readable * even when deleted. Using any other marker value here would be * messy at best.) * n是当前要删除的节点,b是n的前驱节点,f是n的后继节点,开始删除前,(b,n,f)的指向关系如下 * Here's the sequence of events for a deletion of node n with * predecessor b and successor f, initially: * * +------+ +------+ +------+ * ... | b |------>| n |----->| f | ... * +------+ +------+ +------+ * * 1. CAS n's value field from non-null to null. * From this point on, no public operations encountering * the node consider this mapping to exist. However, other * ongoing insertions and deletions might still modify * n's next pointer. * * 1、 将删除节点n的value使用cas设成null,表示此刻起,n节点处于待删除状态,虽然其value为null,对于public相关方法如get等,在执行遇到此类型节点时不会将该节点视为有效节点(也即会被跳过处理),但是如果对于正在执行的插入和删除操作的方法来说,可能也可以去更改“此待删除节点n”的后继节点。 * 2. CAS n's next pointer to point to a new marker node. * From this point on, no other nodes can be appended to n. * which avoids deletion errors in CAS-based linked lists. * * +------+ +------+ +------+ +------+ * ... | b |------>| n |----->|marker|------>| f | ... * +------+ +------+ +------+ +------+ * 2、使用cas将n节点的next字段指向一个marker节点后,从此刻起,任何节点都不会被放在n的后继节点位置,也即不可能出现n->n1、n->n2等,只有n->marker * 3. CAS b's next pointer over both n and its marker. * From this point on, no new traversals will encounter n, * and it can eventually be GCed. * +------+ +------+ * ... | b |----------------------------------->| f | ... * +------+ +------+ * 3、通过cas将b的next指针(越过n节点以及n的后继marker节点)指向f节点,从此刻起,n节点不会被相关操作遍历到,n最终会被GC。
在文章中《深度解析官方关于jdk1.8的resizeStamp的bug处理过程》,我们讨论关于CHM的核心设计——resizeStam需要修复的处理过程,本文再次基于openJDK的bugs讨论组提出的CHM源代码另外一个会造成死循环的bug,默认读者已经掌握CHM的核心源代码实现,否则无法从本文的讨论中获益。文章前部分先把computeIfAbsent的bug成因分析清楚,再来介绍官网ConcurrentHashMap.computeIfAbsent stuck in an endless loop的讨论过程,这样更容易看懂相关内容。
In the above code, condition of (sc == rs + 1 || sc == rs + MAX_RESIZERS ) would never be true , since the value of rs is positive and the value of sc is negative .
The correct condition should be (sc >>> RESIZE_STAMP_SHIFT) == rs + 1 || (sc >>> RESIZE_STAMP_SHIFT) == rs + MAX_RESIZERS, which can be used to dedect if resizing process finished or resizing threads reaches maxmium limitation