之前就知道1.7的hashmap在并发下是存在安全性问题的。
1、值可能会被覆盖
2、死循环的问题
虽然知道有问题,但是没有具体分析过。所以今天就本着好奇看看问题是怎么产生的。
为了看看问题,专门下载了1.7版本的jdk来看看源码
1.7版本源码片段
void transfer(Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length;
for (Entry<K,V> e : table) {
//链表的核心操作就在while循环里面
while(null != e) {
Entry<K,V> next = e.next;
if (rehash) {
e.hash = null == e.key ? 0 : hash(e.key);
}
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
}
}
}
理解一下while操作过程:
1、拿到了entry ==》 entry.next
2、hash操作拿到链表存储在数组上的位置index
3、头插法插数据
4、entry赋值为next,进行下一轮操作
多线程下怎么出现死循环的?
先看看hashmap结构
下面我们看一下链表操作的图解过程:
注:步骤二寻址过程默认几个entry刚好又一次连续放在一个index里面
如果thread2后完成扩容,我们可以看出两个问题:
1、entry3数据丢失;
2、entry1和entry2循环引用了;
注:死循环发生在哪儿?
我没去实际画图的时候,我猜想的是可能线程1和线程2在相互改对方的引用然后一直执行头部插入:1->2->1->2->1…所以到底啥时候会出现死循环呢?
1、下一次扩容的时候;扩容会一直取获取next,直到为null为止,循环引用就没了next为null的时候;CPU又傻逼了,环路上打转转。
2、get entry3的时候,因为entry3丢失了,然后在链表上依次寻找又找不到,然后cpu就开始在一个圈圈上打转转了。