死锁发生的条件
在hashMap扩容时,且在多线程访问时可能发生死锁。
分析
- 生成一个hashMap的初始table。
public static void main(String[] args) {
// 测试 java 7 中哪些数字的 hash 结果相等
System.out.println("长度为16时,桶下标为1的key");
for (int i = 0; i < 64; i++) {
if (hash(i) % 16 == 1) {
System.out.println(i);
}
}
System.out.println("长度为32时,桶下标为1的key");
for (int i = 0; i < 64; i++) {
if (hash(i) % 32 == 1) {
System.out.println(i);
}
}
// 1, 35, 16, 50 当大小为16时,它们在一个桶内
final HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
// 放 12 个元素
map.put(2, null);
map.put(3, null);
map.put(4, null);
map.put(5, null);
map.put(6, null);
map.put(7, null);
map.put(8, null);
map.put(9, null);
map.put(10, null);
//因为链表采用头插法,所以下面三个节点为table[1]的前三个节点
map.put(16, null);
map.put(35, null);
map.put(1, null);
System.out.println("扩容前大小[main]:"+map.size());
new Thread() {
@Override
public void run() {
// 放第 13 个元素, 发生扩容
map.put(50, null);
System.out.println("扩容后大小[Thread-0]:"+map.size());
}
}.start();
new Thread() {
@Override
public void run() {
// 放第 13 个元素, 发生扩容
map.put(50, null);
System.out.println("扩容后大小[Thread-1]:"+map.size());
}
}.start();
}
//hashMap中的哈希函数,用来生成hash值
final static int hash(Object k) {
int h = 0;
if (0 != h && k instanceof String) {
return sun.misc.Hashing.stringHash32((String) k);
}
h ^= k.hashCode();
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
- 主要分析table[1]位置,如下图。
jdk1.7中hashMap死锁详解死锁发生的条件分析 - 如果再插入<50,null>键值对,则数组扩容,将键值对重新分配。源码如下,死锁主要发生在这里。
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;
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;
}
}
}
- 两个线程同时运行,线程0和线程1同时运行到 if(rehash){ 这一行。e和next 的指向如下图。
jdk1.7中hashMap死锁详解死锁发生的条件分析 - 线程0停止,线程1运行完,数组扩容后,键值对会进行重排,如下图。
jdk1.7中hashMap死锁详解死锁发生的条件分析 - 线程0和线程1都是访问的相同的节点,所以当线程1运行完后线程0的指向如下。e还是指向1,next还是指向35。但是线程1将链表的结构改变了。
jdk1.7中hashMap死锁详解死锁发生的条件分析 - 对比线程0先后两种状态,如果线程0继续运行,则会发生死循环。
jdk1.7中hashMap死锁详解死锁发生的条件分析