多线程 HashMap 死循环 问题解析
源码
resize
1 2 3 4 5 6 7 8 9 10 11 12 void resize(int newCapacity) { Entry[] oldTable = table; int oldCapacity = oldTable.length; ...... //创建一个新的Hash Table Entry[] newTable = new Entry[newCapacity]; //将Old Hash Table上的数据迁移到New Hash Table上 transfer(newTable); table = newTable; threshold = (int)(newCapacity * loadFactor); }
迁移
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 void transfer(Entry[] newTable) { Entry[] src = table; int newCapacity = newTable.length; //下面这段代码的意思是: // 从OldTable里摘一个元素出来,然后放到NewTable中 for (int j = 0; j < src.length; j++) { Entry e = src[j]; if (e != null) { src[j] = null; do { Entry next = e.next; int i = indexFor(e.hash, newCapacity); e.next = newTable[i]; newTable[i] = e; e = next; } while (e != null); } } }
我们可以知道newTable 是新创建的 是线程私有的, 因为 线程1 获取 e 和next 之后 线程2 插入执行了,执行完是 倒序的链条, 线程1 再插入 e 和next的 方向 与 线程2执行之后的 方向不对应 导致 循环两次之后 出现问题,会丢数据 ,问题主要集中在最后一次(第3此)执行之后 e,next 均指向null 循环结束
丢数据的问题比较大,
两个线程 ,
1 2 3 4 5 6 7 do { Entry next = e.next; // <--假设线程一执行到这里就被调度挂起了 int i = indexFor(e.hash, newCapacity); e.next = newTable[i]; newTable[i] = e; e = next; } while (e != null);
原来:3 -> 7 -> 6 -> 5( 数据5 resize的时候 分到了其他数组 这里不管它 )
线程1 在 上图位置 卡住, e1 指向3 和 next1 指向 7
线程2 执行
执行后结果为 6 -> 7 -> 3 -> null
ps:没什么画图工具 手画了一下
参考文章:http://blog.csdn.net/xiaohui127/article/details/11928865