VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > Java教程 >
  • JDK1.7HashMap死锁

在看之前可以先看看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;

这里已经出现问题了,两个节点互相引用

__EOF__

 
本文作者Jame 本文链接:https://www.cnblogs.com/sunankang/p/15084809.html


相关教程