1 | for (int j = 0; j < src.length; ++j) { |
举例说明下:
原
table
的信息排列是:
再次添加新元素的时候就需要扩容了,此时我们来类比下上述的代码:
1 | for (int j = 0; j < src.length; ++j) { |
变成如下:
上述是属于正常情况的那种,假设我们现在有两个线程同时去 put
元素,二者均发现需要做扩容处理,那么又会出现什么情况呢?
参考阅读网上的博客+自己理解记录
当线程一 和 线程二 同时进行插入的时候刚好达到扩容的条件,然后同时开始进行 Resize
操作。
1 | for (int j = 0; j < src.length; ++j) { |
线程一挂起,线程二继续操作,变成如下:
线程二是 rehash
之后的样子,如上图:
当前线程一来说:
e
是: key(3)
next
是: key(7)
线程一来了,被调度回来了,该人家执行了:
1 |
|
这样就产生死循环了。
1 | key(7).next 指向 key(3) |
当我们取出一个key(5) 的一个值时,恰巧也是 int i = 3
, 这样去取,就陷入key(3),key(7)
的死循环中去了。
为了更清晰的展示每一次循环,我决定分开来展示:
第一次:要从这个线程一恢复运行开始说起吧: e: key(3) ; next: key(7)
1 | while(null != e) { |
OK, 由于e = key(7)
不为null
,循环继续:
第二次循环:经过上述循环,此时 e: key(7),next: key(3)
由于线程二已经改变了这个整体table
的结构,当遍历到key(7)
时, next: key(3)
1 | while(null != e) {//e:key(7) |
第三次循环:e : key(3) next:null
1 | while(null != e) {//e:key(3) |
此时 e : null, next:null
.
1 | //key(7).next指向key(3) |
图就是这样的:最后newTable[3] = key(3)
over.