Jdk1.8中的循环链
说到HashMap的循环链,应该就会想到一些关键字:jdk1.7,链表,多线程,扩容,头插法。jdk1.8的时候,新增了红黑树结构,头插法也改成了尾插法,所以,Jdk1.8的hashmap就没有循环链了吗?
jdk1.7
先简单说说1.7的循环链形成吧,核心代码如图
步骤
- 一条链表A->B->null;
- 线程1准备扩容时,此时链表上的A.next = B,然后被挂起;
- 线程2扩容时,把A,B两个对象都rehash了,恰好又在一条链上,由于是头插法,现在B.next=A;
- 线程1接着扩容,rehashA对象,放在链表上,接着rehashB对象,放在链表上
- 由于线程2的原因,B.next=A,线程一发现B.next不为空,接着reHashA,结果形成循环链A->B->A;
JDK1.8
-
jdk1.8的链表,增加了一个尾部指针,所以插入的时候,直接插入在链表尾部,避免了循环链
-
但是1.8是在链表转换树或者对树进行操作的时候会出现线程安全的问题,两个红黑树节点的父亲节点相互引用才可以导致无法走出这个for语句
- balanceInsertion()方法对树进行一个重新的平衡时,也会出现线程安全问题,可能Node节点转换为TreeNode结点异常
总结:
主要原因其实是多线程下操作同一对象时,对象内部属性的不一致性导致的。分析方式跟为什么单例要使用双重锁check类似