Segment[] segments,每個 Segment 繼承 ReentrantLock,內含 HashEntry<K,V>[] table。volatile 保證可見性),寫操作鎖 Segment。transient volatile Node<K,V>[] table 存儲數據。i = (n-1) & hash。tab[i] == null,用 casTabAt (Unsafe CAS) 無鎖插入首節點。hash == MOVED,協助擴容。TREEIFY_THRESHOLD (默認 8) 且數組長度 ≥ MIN_TREEIFY_CAPACITY (64) 時,treeifyBin 轉為紅黑樹(TreeBin 包裝 TreeNode)。UNTREEIFY_THRESHOLD (6) 時退化為鏈表。final V putVal(K key, V value, boolean onlyIfAbsent) {
if (key == null || value == null) throw new NullPointerException();
int hash = spread(key.hashCode());
for (Node<K,V>[] tab = table;;) {
Node<K,V> f; int n, i, fh;
if (tab == null || (n = tab.length) == 0)
tab = initTable();
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
if (casTabAt(tab, i, null, new Node<>(hash, key, value, null)))
break; // 無鎖插入成功
}
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f); // 協助擴容
else {
V oldVal = null;
synchronized (f) { // 鎖住 bin 首節點
if (tabAt(tab, i) == f) {
if (fh >= 0) { // 鏈表
// 遍歷更新或尾插
}
else if (f instanceof TreeBin) { // 紅黑樹
// putTreeVal
}
}
}
if (binCount >= TREEIFY_THRESHOLD) treeifyBin(tab, i);
}
}
addCount(1L, binCount);
return null;
}
| JDK 版本 | put 耗時 (ms) | get 耗時 (ms) |
|---|---|---|
| 1.7 | ~ 185 | ~ 42 |
| 1.8 | ~ 95 | ~ 28 |
| 提升 | ~48% | ~33% |
1.8 在高併發寫入場景優勢明顯,得益於更細鎖粒度與無鎖 CAS 插入。
size() 需遍歷所有 Segment 加鎖求和,慢且阻塞。CounterCell[] 分段計數器,addCount 以 CAS/細鎖更新,size() 無鎖求和,性能數量級提升。