Skip to content

Commit 3453b2f

Browse files
authored
更新 ConcurrentHashMap 1.7 扩容存在两次 for 循环的原因
1 parent 9bdb5f6 commit 3453b2f

File tree

1 file changed

+13
-1
lines changed

1 file changed

+13
-1
lines changed

docs/java/collection/concurrent-hash-map-source-code.md

+13-1
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,19 @@ private void rehash(HashEntry<K,V> node) {
368368
}
369369
```
370370

371-
有些同学可能会对最后的两个 for 循环有疑惑,这里第一个 for 是为了寻找这样一个节点,这个节点后面的所有 next 节点的新位置都是相同的。然后把这个作为一个链表赋值到新位置。第二个 for 循环是为了把剩余的元素通过头插法插入到指定位置链表。这样实现的原因可能是基于概率统计,有深入研究的同学可以发表下意见。
371+
有些同学可能会对最后的两个 for 循环有疑惑,这里第一个 for 是为了寻找这样一个节点,这个节点后面的所有 next 节点的新位置都是相同的。然后把这个作为一个链表赋值到新位置。第二个 for 循环是为了把剩余的元素通过头插法插入到指定位置链表。~~这样实现的原因可能是基于概率统计,有深入研究的同学可以发表下意见。~~
372+
373+
内部第二个 `for` 循环中使用了 `new HashEntry<K,V>(h, p.key, v, n)` 创建了一个新的 `HashEntry`,而不是复用之前的,是因为如果复用之前的,那么会导致正在遍历(如正在执行 `get` 方法)的线程由于指针的修改无法遍历下去。正如注释中所说的:
374+
375+
> 当它们不再被可能正在并发遍历表的任何读取线程引用时,被替换的节点将被垃圾回收。
376+
>
377+
> The nodes they replace will be garbage collectable as soon as they are no longer referenced by any reader thread that may be in the midst of concurrently traversing table
378+
379+
为什么需要再使用一个 `for` 循环找到 `lastRun` ,其实是为了减少对象创建的次数,正如注解中所说的:
380+
381+
> 从统计上看,在默认的阈值下,当表容量加倍时,只有大约六分之一的节点需要被克隆。
382+
>
383+
> Statistically, at the default threshold, only about one-sixth of them need cloning when a table doubles.
372384
373385
### 5. get
374386

0 commit comments

Comments
 (0)