条件:
- 多线程同时保存数据,同时触发HashMap扩容;
- 存在某一节点上的链表内至少2个节点在新算的位置上相同;
原因:
- 1.7 HashMap采用头插法,以至于存入顺序与读取(保存链表内)的顺序相反;
- 当第一个线程完成扩容计算后,并没有马上把原数组替换成新数组,所以其他线程还会继续操作原数组,但是,原数组里的链表顺序已经改变;
- 其他线程执行扩容计算时,再次改变链表顺序,导致产生环路。
do {
Entry<K,V> next = e.next;
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
} while (e != null);
例如:
原数组:A->B->C,即oldTable[key]=A; A.next=B; B.next=C; C.next=null
按时间顺序执行:
线程一:
e=A; next=e.next=B;
线程二:
e=A; next=e.next=B;
线程一:
e.next=A.next=newTable[key]=null;
newTable[key]=e=A;
e=next=B;
next=e.next=B.next=C;
e.next=B.next=newTable[key]=A;
newTable[key]=e=B;
线程二:
e.next=A.next=newTable[key]=null;
newTable[key]=e=A;
e=next=B;
next=e.next=B.next=A; (线程一执行结果)
e.next=B.next=newTable[key]=A;
newTable[key]=e=B;
e=next=A;
至此已经形成循环
2020-07-14
网友评论