JDK1.7HashMap死锁
JDK1.7HashMap死锁
JDK1.7HashMap多线程问题
Java技术交流群:737698533
在看之前可以先看看JDK1.7的Hashmap的源码
HashMap在多线程情况下是不安全的,一个是数据的准确性问题,一个就是可能会出现死锁问题
出现死锁的情况在扩容的代码里,假设现在有两个线程都在对下图的Map进行操作
这个HashMap设置了初始大小为4,负载因子为0.75,现在又添加一个元素D,很不幸通过indexOf方法算出的下标也是在下标0的位置
根据扩容的判断条件if ((size >= threshold) && (null != table[bucketIndex]))
总元素个数为3>=(数组长度4*负载因子0.75)
而且添加的位置不为空,所以进入扩容方法
现在有T1和T2两个线程同时进行添加操作,同时进行扩容
void transfer(Entry[] newTable, boolean rehash) { int newCapacity = newTable.length; for (Entry<k,v> e : table) { while(null != e) { Entry<k,v> next = e.next; //假设在这个位置T2时间片用完 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; } } }
假设T2因为时间片用完轮到T1执行,那么此时T2线程的变量赋值如下,后面的数组就不画了
T1创建新的数组然后将数据转移,完成后T2醒来,如下图所示
注意当T1将数据移动后,数据顺序反了,可以看看上面的代码推理一下,那么假设现在线程T2醒来,继续执行代码
主要代码如下,下面一步代码对比一个图
while(null != e) { Entry<k,v> next = e.next; //醒来继续执行,计算下标 int i = indexFor(e.hash, newCapacity); e.next = newTable[i]; newTable[i] = e; e = next; }
e.next = newTable[i];
newTable[i] = e;
e = next;
回到循环,判断e不为空,继续执行
Entry<k,v> next = e.next;
然后计算下标,继续代码
e.next = newTable[i];
newTable[i] = e;
e = next;
继续循环,e不为空
Entry<k,v> next = e.next;
e.next = newTable[i];
newTable[i] = e;
e = next;
这里已经出现问题了,两个节点互相引用