ConcurrentHashMap
ConcurrentHashMap 能解决什么问题?什么时候使用 ConcurrentHashMap?
1)ConcurrentHashMap 支持高并发的读写,是线程安全的哈希表。
2)ConcurrentHashMap 的键和值都不能为 null。
3)ConcurrentHashMap 是弱一致性的,写操作变更的数据不一定能立即被其他线程读取。
如何使用 ConcurrentHashMap?
1)需要并发读写对象映射关系的场景下。
2)ConcurrentHashMap 常用于本地缓存。
使用 ConcurrentHashMap 有什么风险?
1)ConcurrentHashMap 是弱一致性的。
ConcurrentHashMap 核心操作的实现原理?
创建实例
/**
* ConcurrentHashMap 的最大容量
*/
private static final int MAXIMUM_CAPACITY = 1 << 30;
/**
* ConcurrentHashMap 的初始化容量
*/
private static final int DEFAULT_CAPACITY = 16;
/**
* The largest possible (non-power of two) array size.
* Needed by toArray and related methods.
*/
static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* ConcurrentHashMap 的默认并发度
*/
private static final int DEFAULT_CONCURRENCY_LEVEL = 16;
/**
* ConcurrentHashMap 的加载因子,覆盖该值只会影响其初始容量。
*/
private static final float LOAD_FACTOR = 0.75f;
/**
* 链表红黑树化的长度阈值
*/
static final int TREEIFY_THRESHOLD = 8;
/**
* 红黑树链表化的长度阈值
*/
static final int UNTREEIFY_THRESHOLD = 6;
/**
* bucket 链表红黑树化的最小 bucket 数,
* 即 ConcurrentHashMap 的容量必须达到 64 才会执行红黑树化操作
*/
static final int MIN_TREEIFY_CAPACITY = 64;
/**
* 扩容过程中,单个线程最少负责从旧 table 中转移的 bucket 数目,
* 以支持多线程扩容。
*/
private static final int MIN_TRANSFER_STRIDE = 16;
/**
* 用于生成 sizeCtl 标记的位的数目
* Must be at least 6 for 32bit arrays.
*/
private static final int RESIZE_STAMP_BITS = 16;
/**
* 能够帮助扩容的最大线程数量
* Must fit in 32 - RESIZE_STAMP_BITS bits.
*/
private static final int MAX_RESIZERS = (1 << 32 - ConcurrentHashMap.RESIZE_STAMP_BITS) - 1;
/**
* The bit shift for recording size stamp in sizeCtl.
*/
private static final int RESIZE_STAMP_SHIFT = 32 - ConcurrentHashMap.RESIZE_STAMP_BITS;
/*
* Encodings for Node hash fields. See above for explanation.
*/
static final int MOVED = -1; // ForwardingNode 节点的哈希值
static final int TREEBIN = -2; // TreeBin 节点的哈希值
static final int RESERVED = -3; // ReservationNode 节点的哈希值
static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash
/** 当前 JVM 可用的 CPU 数目 */
static final int NCPU = Runtime.getRuntime().availableProcessors();
/**
* 在第一次插入时执行初始化
*/
transient volatile Node<K,V>[] table;
/**
* 扩容过程中的新 table,只有在扩容时才有值,其他时间为 null
*/
private transient volatile Node<K,V>[] nextTable;
/**
* 没有发生竞争或表初始化期间,累元素总数的基础值
*/
private transient volatile long baseCount;
/**
* -1:哈希表正在执行初始化
* -N:哈希表正在扩容
* 20:ConcurrentHashMap 实例新建
* +N:下一次扩容的阈值
*/
private transient volatile int sizeCtl;
/**
* 扩容过程中,下一个允许分割的索引
*/
private transient volatile int transferIndex;
/**
* resizing and/or creating CounterCells 的标记值
*/
private transient volatile int cellsBusy;
/**
* 并发累加元素总数的单元
*/
private transient volatile CounterCell[] counterCells;
/**
* 创建一个初始容量为 16 的空 ConcurrentHashMap 实例
*/
public ConcurrentHashMap() {
}
/**
* 创建一个初始容量为【最接近 initialCapacity 的 2 的幂】的空 ConcurrentHashMap 实例
*/
public ConcurrentHashMap(int initialCapacity) {
if (initialCapacity < 0) {
throw new IllegalArgumentException();
}
final int cap = initialCapacity >= ConcurrentHashMap.MAXIMUM_CAPACITY >>> 1 ?
ConcurrentHashMap.MAXIMUM_CAPACITY :
ConcurrentHashMap.tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1);
this.sizeCtl = cap;
}
添加元素
/**
* 往 ConcurrentHashMap 实例中添加新的键值对,键和值都不能为 null
*/
@Override
public V put(K key, V value) {
return putVal(key, value, false);
}
/** Implementation for put and putIfAbsent */
/**
* @param key 键
* @param value 值
* @param onlyIfAbsent 只有键不存在时才添加
*/
final V putVal(K key, V value, boolean onlyIfAbsent) {
// 非空判断
if (key == null || value == null) {
throw new NullPointerException();
}
// 计算哈希值
final int hash = ConcurrentHashMap.spread(key.hashCode());
int binCount = 0;
// 读取 table
for (Node<K,V>[] tab = table;;) {
/**
* f:first 表示 bucket 的首元素
* n:length 表示 table 长度
* i:index 表示目标索引
* fh:first hash 表示首元素的哈希值
* fk:first key 表示首元素的键
* fv:first value 表示首元素的值
*/
Node<K,V> f; int n, i, fh; K fk; V fv;
// 1)table 为空,则表示 ConcurrentHashMap 还未初始化
if (tab == null || (n = tab.length) == 0) {
// 执行初始化操作
tab = initTable();
// 2)通过哈希值定位到的 bucket 为 null
} else if ((f = ConcurrentHashMap.tabAt(tab, i = n - 1 & hash)) == null) {
// 则基于给定键和值创建新的节点,并尝试通过原子操作写入 bucket
if (ConcurrentHashMap.casTabAt(tab, i, null, new Node<>(hash, key, value)))
{
// 写入成功,则直接返回
break; // no lock when adding to empty bin
}
}
// 3)首节点的哈希值为 MOVED 表示当前哈希表在扩容
else if ((fh = f.hash) == ConcurrentHashMap.MOVED) {
// 尝试帮助进行元素迁移
tab = helpTransfer(tab, f);
// 4)如果是 onlyIfAbsent 模式,并且键已经存在,其值不为 null,则直接返回旧值
} else if (onlyIfAbsent // check first node without acquiring lock
&& fh == hash
&& ((fk = f.key) == key || fk != null && key.equals(fk))
&& (fv = f.val) != null) {
return fv;
// 5)将节点加入到链表或红黑树中
} else {
V oldVal = null;
// 获取 bucket 首节点的对象监视器实现线程同步
synchronized (f) {
// 如果首节点已经变更,则出现了并发写,需要重新进行处理
if (ConcurrentHashMap.tabAt(tab, i) == f) {
// 1)当前 bucket 是否是链表
if (fh >= 0) {
binCount = 1;
// 遍历链表中的每个节点
for (Node<K,V> e = f;; ++binCount) {
K ek;
// 如果找到匹配的节点
if (e.hash == hash &&
((ek = e.key) == key ||
ek != null && key.equals(ek))) {
// 读取旧值
oldVal = e.val;
// 尝试写入新值
if (!onlyIfAbsent) {
e.val = value;
}
// 退出循环
break;
}
final Node<K,V> pred = e;
/**
* 读取当前节点的后置节点,如果其为 null 则说明到达了链表尾部
*/
if ((e = e.next) == null) {
// 直接在尾部新增节点
pred.next = new Node<>(hash, key, value);
// 退出循环
break;
}
}
}
// 2)当前 bucket 是否是红黑树
else if (f instanceof TreeBin) {
Node<K,V> p;
binCount = 2;
// 尝试在红黑树中新增节点
if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
value)) != null) {
// 读取旧值
oldVal = p.val;
// 尝试写入新值
if (!onlyIfAbsent) {
p.val = value;
}
}
}
else if (f instanceof ReservationNode) {
throw new IllegalStateException("Recursive update");
}
}
}
if (binCount != 0) {
// 单向链表的长度已经达到红黑树化阈值 8+1
if (binCount >= ConcurrentHashMap.TREEIFY_THRESHOLD) {
// 执行链表的红黑树化过程
treeifyBin(tab, i);
}
if (oldVal != null) {
return oldVal;
}
break;
}
}
}
// 增加元素计数值
addCount(1L, binCount);
return null;
}
/**
* 使用记录在 sizeCtl 中的值初始化哈希表.
*/
private final Node<K,V>[] initTable() {
Node<K,V>[] tab; int sc;
while ((tab = table) == null || tab.length == 0) {
// 1)已经有其他线程在执行初始化操作
if ((sc = sizeCtl) < 0) {
// 当前线程让出 CPU 等待其他线程初始化完毕
Thread.yield(); // lost initialization race; just spin
// 2)原子更新 SIZECTL 的值为 -1
} else if (ConcurrentHashMap.U.compareAndSetInt(this, ConcurrentHashMap.SIZECTL, sc, -1)) {
try {
if ((tab = table) == null || tab.length == 0) {
final int n = sc > 0 ? sc : ConcurrentHashMap.DEFAULT_CAPACITY;
// 新建 table
final
Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
// 写入 table
table = tab = nt;
// 计算 sizeCtl
sc = n - (n >>> 2);
}
} finally {
// 写入 sizeCtl
sizeCtl = sc;
}
break;
}
}
return tab;
}
/**
* 如果哈希表正在执行扩容,则尝试帮助转移旧 table 中的元素到新 table 中
*/
final Node<K,V>[] helpTransfer(Node<K,V>[] tab, Node<K,V> f) {
Node<K,V>[] nextTab; int sc;
/**
* 1)首节点是 ForwardingNode &&
* 2)首节点的 nextTable 存在
*/
if (tab != null && f instanceof ForwardingNode &&
(nextTab = ((ForwardingNode<K,V>)f).nextTable) != null) {
// 读取用于扩容长度为 tab.length 的哈希表的标记
final int rs = ConcurrentHashMap.resizeStamp(tab.length);
while (nextTab == nextTable && table == tab &&
(sc = sizeCtl) < 0) {
// 如果帮助扩容的线程已经满了或已经迁移完毕
if (sc >>> ConcurrentHashMap.RESIZE_STAMP_SHIFT != rs || sc == rs + 1 ||
sc == rs + ConcurrentHashMap.MAX_RESIZERS || transferIndex <= 0) {
// 直接退出
break;
}
// 尝试加入扩容大军
if (ConcurrentHashMap.U.compareAndSetInt(this, ConcurrentHashMap.SIZECTL, sc, sc + 1)) {
// 加入成功则执行旧 table 的迁移
transfer(tab, nextTab);
break;
}
}
return nextTab;
}
return table;
}
/**
* Replaces all linked nodes in bin at given index unless table is
* too small, in which case resizes instead.
*/
private final void treeifyBin(Node<K,V>[] tab, int index) {
Node<K,V> b; int n;
if (tab != null) {
// 1)哈希表的容量小于 64
if ((n = tab.length) < ConcurrentHashMap.MIN_TREEIFY_CAPACITY) {
// 执行双倍扩容
tryPresize(n << 1);
// 2)读取 bucket 首节点后进行红黑树化
} else if ((b = ConcurrentHashMap.tabAt(tab, index)) != null && b.hash >= 0) {
synchronized (b) {
// 如果没有其他线程并发修改此 bucket
if (ConcurrentHashMap.tabAt(tab, index) == b) {
/**
* hd:head
* tl:tail
*/
TreeNode<K,V> hd = null, tl = null;
// 遍历单向链表,将所有的节点装换为树节点
for (Node<K,V> e = b; e != null; e = e.next) {
final TreeNode<K,V> p =
new TreeNode<>(e.hash, e.key, e.val,
null, null);
if ((p.prev = tl) == null) {
hd = p;
} else {
tl.next = p;
}
tl = p;
}
// 执行红黑树化过程
ConcurrentHashMap.setTabAt(tab, index, new TreeBin<>(hd));
}
}
}
}
}
/**
* 尝试进行扩容
*/
private final void tryPresize(int size) {
final int c = size >= ConcurrentHashMap.MAXIMUM_CAPACITY >>> 1 ? ConcurrentHashMap.MAXIMUM_CAPACITY :
ConcurrentHashMap.tableSizeFor(size + (size >>> 1) + 1);
int sc;
// 当前还未执行扩容操作
while ((sc = sizeCtl) >= 0) {
final Node<K,V>[] tab = table; int n;
// 1)table 为空,则执行初始化操作
if (tab == null || (n = tab.length) == 0) {
n = sc > c ? sc : c;
if (ConcurrentHashMap.U.compareAndSetInt(this, ConcurrentHashMap.SIZECTL, sc, -1)) {
try {
if (table == tab) {
@SuppressWarnings("unchecked")
final
Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
table = nt;
sc = n - (n >>> 2);
}
} finally {
sizeCtl = sc;
}
}
}
// 2)目标 size 小于扩容阈值或 table 容量超出最大容量
else if (c <= sc || n >= ConcurrentHashMap.MAXIMUM_CAPACITY) {
break;
// 3)没有其他线程执行扩容操作
} else if (tab == table) {
final int rs = ConcurrentHashMap.resizeStamp(n);
// 尝试原子更新控制标识
if (ConcurrentHashMap.U.compareAndSetInt(this, ConcurrentHashMap.SIZECTL, sc,
(rs << ConcurrentHashMap.RESIZE_STAMP_SHIFT) + 2)) {
// 更新成功则执行旧 table 的数据迁移
transfer(tab, null);
}
}
}
}
/**
* 将旧 table 中的 bucket 迁移到新 table 中
*/
private final void transfer(Node<K,V>[] tab, Node<K,V>[] nextTab) {
// 旧table的长度
final int n = tab.length;
// 当前线程连续迁移的 bucket 数,一般都是 16
int stride;
if ((stride = ConcurrentHashMap.NCPU > 1 ? (n >>> 3) / ConcurrentHashMap.NCPU : n) < ConcurrentHashMap.MIN_TRANSFER_STRIDE)
{
stride = ConcurrentHashMap.MIN_TRANSFER_STRIDE; // subdivide range
}
// 如果当前线程是第一个执行扩容的线程,则执行新 table 的初始化
if (nextTab == null) { // initiating
try {
@SuppressWarnings("unchecked")
final
// 双倍扩容
Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1];
nextTab = nt;
} catch (final Throwable ex) { // try to cope with OOME
sizeCtl = Integer.MAX_VALUE;
return;
}
// 写入新 table
nextTable = nextTab;
// 写入下一个迁移的起始索引
transferIndex = n;
}
final int nextn = nextTab.length;
// 创建 ForwardingNode
final ForwardingNode<K,V> fwd = new ForwardingNode<>(nextTab);
// 是否能处理下一个 bucket
boolean advance = true;
// 是否完成扩容
boolean finishing = false; // to ensure sweep before committing nextTab
// 死循环扩容
for (int i = 0, bound = 0;;) {
/**
* f:first 表示首节点
* fh:first hash 表示首节点的哈希值
*/
Node<K,V> f; int fh;
// 如果能处理下一个 bucket
while (advance) {
int nextIndex, nextBound;
/**
* 1)递减bucket下标,如果已经达到当次处理的最小下标,则需要重新申领
* 2)扩容已完成,则尝试进行二次校验
*/
if (--i >= bound || finishing) {
// 当前 bucket 未迁移
advance = false;
// 2)读取迁移索引,如果迁移索引为 0,表示所有的 bucket 已经申领完毕
} else if ((nextIndex = transferIndex) <= 0) {
i = -1;
advance = false;
}
// 3)尝试申领新的一段 buckets
else if (ConcurrentHashMap.U.compareAndSetInt
(this, ConcurrentHashMap.TRANSFERINDEX, nextIndex,
nextBound = nextIndex > stride ?
nextIndex - stride : 0)) {
// 更新本次能迁移的最小 bucket 索引
bound = nextBound;
// 读取本次迁移的起始 bucket 索引
i = nextIndex - 1;
advance = false;
}
}
/**
* 申领的 bucket 已经全部迁移完毕
*/
if (i < 0 || i >= n || i + n >= nextn) {
int sc;
// 1)如果已经扩容完成
if (finishing) {
nextTable = null;
// 写入新 table
table = nextTab;
// 写入新 sizeCtl
sizeCtl = (n << 1) - (n >>> 1);
return;
}
// 当前线程完成了其申领 buckets 的迁移工作
if (ConcurrentHashMap.U.compareAndSetInt(this, ConcurrentHashMap.SIZECTL, sc = sizeCtl, sc - 1)) {
/**
* 如果不是最后一个完成迁移的线程
* 1)第一个执行扩容的线程会将 sizeCtl 设置为 ConcurrentHashMap.resizeStamp(n) << ConcurrentHashMap.RESIZE_STAMP_SHIFT + 2
* 2)每个帮助扩容的线程申领到 buckets 会将其 +1,完成申领 buckets 迁移工作后会将其 -1
* 3)如果当前线程是最后一个完成迁移工作的线程,则其值为 ConcurrentHashMap.resizeStamp(n) << ConcurrentHashMap.RESIZE_STAMP_SHIFT + 2
*/
if (sc - 2 != ConcurrentHashMap.resizeStamp(n) << ConcurrentHashMap.RESIZE_STAMP_SHIFT) {
// 则直接返回
return;
}
// 最后一个扩容线程将会设置完成标志,并执行二次校验
finishing = advance = true;
i = n; // recheck before commit
}
}
/**
* 2)如果旧 table 的指定 bucket 为 null,表示无需执行数据迁移,
* 则直接将其设置为 ForwardingNode
*/
else if ((f = ConcurrentHashMap.tabAt(tab, i)) == null) {
advance = ConcurrentHashMap.casTabAt(tab, i, null, fwd);
/**
* 3)执行迁移完成的二次校验,当前 bucket 已经处理过了
*/
} else if ((fh = f.hash) == ConcurrentHashMap.MOVED) {
advance = true; // already processed
// 4)迁移指定 bucket
} else {
synchronized (f) {
// 处理过程中未发生并发修改
if (ConcurrentHashMap.tabAt(tab, i) == f) {
/**
* ln:low node 表示低位节点
* hn:high node 表示高位节点
*/
Node<K,V> ln, hn;
// 1)当前 bucket 是单向链表
if (fh >= 0) {
// 将节点哈希值和table长度进行与操作
int runBit = fh & n;
// 读取最后处理的节点
Node<K,V> lastRun = f;
for (Node<K,V> p = f.next; p != null; p = p.next) {
final int b = p.hash & n;
if (b != runBit) {
runBit = b;
lastRun = p;
}
}
// 最后一个处理的节点哈希值 < 2^n
if (runBit == 0) {
// 写入低位节点
ln = lastRun;
hn = null;
}
else {
// 写入高位节点
hn = lastRun;
ln = null;
}
for (Node<K,V> p = f; p != lastRun; p = p.next) {
final int ph = p.hash; final K pk = p.key; final V pv = p.val;
// 当前节点是低位节点
if ((ph & n) == 0) {
ln = new Node<>(ph, pk, pv, ln);
// 当前节点是高位节点
} else {
hn = new Node<>(ph, pk, pv, hn);
}
}
// 将处理后的 bucket 写入新table的低位
ConcurrentHashMap.setTabAt(nextTab, i, ln);
// 将处理后的 bucket 写入新table的高位
ConcurrentHashMap.setTabAt(nextTab, i + n, hn);
// 更新旧table的 bucket为ForwardingNode,表示当前bucket已经完成迁移
ConcurrentHashMap.setTabAt(tab, i, fwd);
// 继续处理下一个 bucket
advance = true;
}
// 2)当前 bucket 是红黑树
else if (f instanceof TreeBin) {
final TreeBin<K,V> t = (TreeBin<K,V>)f;
/**
* lo:low
* hi:high
* loTail:lowTail
* hiTail:highTail
* lc:low count
* hc:high count
*/
TreeNode<K,V> lo = null, loTail = null;
TreeNode<K,V> hi = null, hiTail = null;
int lc = 0, hc = 0;
// 从首节点开始处理
for (Node<K,V> e = t.first; e != null; e = e.next) {
final int h = e.hash;
final TreeNode<K,V> p = new TreeNode<>
(h, e.key, e.val, null, null);
if ((h & n) == 0) {
// 低位首节点为空
if ((p.prev = loTail) == null) {
// 写入首节点
lo = p;
} else {
// 写入后继节点
loTail.next = p;
}
loTail = p;
++lc;
}
else {
// 高位首节点为空
if ((p.prev = hiTail) == null) {
// 写入首节点
hi = p;
} else {
// 写入后继节点
hiTail.next = p;
}
hiTail = p;
++hc;
}
}
// 是否需要执行红黑树的链表化
ln = lc <= ConcurrentHashMap.UNTREEIFY_THRESHOLD ? ConcurrentHashMap.untreeify(lo) :
hc != 0 ? new TreeBin<>(lo) : t;
hn = hc <= ConcurrentHashMap.UNTREEIFY_THRESHOLD ? ConcurrentHashMap.untreeify(hi) :
lc != 0 ? new TreeBin<>(hi) : t;
// 写入新 table 的 bucket 中
ConcurrentHashMap.setTabAt(nextTab, i, ln);
ConcurrentHashMap.setTabAt(nextTab, i + n, hn);
ConcurrentHashMap.setTabAt(tab, i, fwd);
// 继续处理下一个 bucket
advance = true;
}
}
}
}
}
}
读取元素
/**
* 根据键读取值,如果键不存在,则返回 null
*/
@Override
public V get(Object key) {
Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
final int h = ConcurrentHashMap.spread(key.hashCode());
// table 不为空,并且通过键的哈希值映射的 bucket 首节点不为 null
if ((tab = table) != null && (n = tab.length) > 0 &&
(e = ConcurrentHashMap.tabAt(tab, n - 1 & h)) != null) {
// 1)首节点哈希值和目标键的哈希值一致
if ((eh = e.hash) == h) {
// 同时键也相等
if ((ek = e.key) == key || ek != null && key.equals(ek)) {
// 直接返回值
return e.val;
}
}
// 2)当前 bucket 是红黑树或正在执行扩容,则使用 find 方法查找键
else if (eh < 0) {
// 找到则返回其值,否则返回 null
return (p = e.find(h, key)) != null ? p.val : null;
}
// 当前 bucket 是一个单向链表,则执行链表查找
while ((e = e.next) != null) {
if (e.hash == h &&
((ek = e.key) == key || ek != null && key.equals(ek))) {
return e.val;
}
}
}
// 未找到键,则返回 null
return null;
}
/**
* 如果目标键存在,则返回其关联的值,否则返回默认值
*/
@Override
public V getOrDefault(Object key, V defaultValue) {
V v;
return (v = get(key)) == null ? defaultValue : v;
}
替换值
/**
* 如果存在目标键,则替换其值,并返回旧值;否则返回 null
*/
@Override
public V replace(K key, V value) {
if (key == null || value == null) {
throw new NullPointerException();
}
return replaceNode(key, value, null);
}
final V replaceNode(Object key, V value, Object cv) {
// 计算 key 的哈希值
final int hash = ConcurrentHashMap.spread(key.hashCode());
// 读取 table 后进入死循环
for (Node<K,V>[] tab = table;;) {
Node<K,V> f; int n, i, fh;
// 1)table 为空,或通过哈希值定位的 bucket 为空,则直接返回 null
if (tab == null || (n = tab.length) == 0 ||
(f = ConcurrentHashMap.tabAt(tab, i = n - 1 & hash)) == null) {
break;
// 2)table 正在扩容,则尝试帮助其扩容
} else if ((fh = f.hash) == ConcurrentHashMap.MOVED) {
tab = helpTransfer(tab, f);
// 执行键查找
} else {
V oldVal = null;
boolean validated = false;
// 锁住头结点
synchronized (f) {
// 头结点未发生变更
if (ConcurrentHashMap.tabAt(tab, i) == f) {
// 1)当前 bucket 是链表
if (fh >= 0) {
validated = true;
for (Node<K,V> e = f, pred = null;;) {
K ek;
if (e.hash == hash &&
((ek = e.key) == key ||
ek != null && key.equals(ek))) {
// 找到了匹配的键
final V ev = e.val;
/**
* 1)cv==null 表示无条件替换
* 2)cv == ev || ev != null && cv.equals(ev) 表示 cas 替换
*/
if (cv == null || cv == ev ||
ev != null && cv.equals(ev)) {
// 读取旧值
oldVal = ev;
// 1)目标值不为 null,则表示节点替换
if (value != null) {
e.val = value;
/**
* 2)目标值为 null 则表示节点删除
* pred != null 表示当前节点在首节点之后
*/
} else if (pred != null) {
pred.next = e.next;
// pred == null 表示当前节点是首节点,则直接 cas 更新为第二个节点
} else {
ConcurrentHashMap.setTabAt(tab, i, e.next);
}
}
break;
}
// 继续查找下一个节点
pred = e;
// 如果已经达到尾部,则表示未找到匹配的键
if ((e = e.next) == null) {
break;
}
}
}
// 2)当前 bucket 是红黑树
else if (f instanceof TreeBin) {
validated = true;
final TreeBin<K,V> t = (TreeBin<K,V>)f;
TreeNode<K,V> r, p;
// 读取根节点 && 执行树节点查找
if ((r = t.root) != null &&
(p = r.findTreeNode(hash, key, null)) != null) {
final V pv = p.val;
/**
* 1)cv==null 表示无条件替换
* 2)cv == ev || ev != null && cv.equals(ev) 表示 cas 替换
*/
if (cv == null || cv == pv ||
pv != null && cv.equals(pv)) {
oldVal = pv;
// 1)目标值不为 null,则表示节点替换
if (value != null) {
p.val = value;
// 2)目标值为 null,则表示节点删除
} else if (t.removeTreeNode(p)) {
ConcurrentHashMap.setTabAt(tab, i, ConcurrentHashMap.untreeify(t.first));
}
}
}
}
else if (f instanceof ReservationNode) {
throw new IllegalStateException("Recursive update");
}
}
}
// 已经完成查找
if (validated) {
if (oldVal != null) {
if (value == null) {
// 旧值不为 null,新值为 null 表示删除了一个存在的节点,递减总数
addCount(-1L, -1);
}
return oldVal;
}
break;
}
}
}
return null;
}
/**
* 如果键 key 存在 && 旧值和 oldValue 相等,则将其替换为 newValue
*/
@Override
public boolean replace(K key, V oldValue, V newValue) {
if (key == null || oldValue == null || newValue == null) {
throw new NullPointerException();
}
return replaceNode(key, newValue, oldValue) != null;
}
节点删除
/**
* 指定的 key 存在,则删除节点并返回旧值;否则返回 null
*/
@Override
public V remove(Object key) {
return replaceNode(key, null, null);
}
/**
* 如果 key 存在 && 旧值和 value 相等,则将其删除,删除成功返回 true,否则返回 false
*/
@Override
public boolean remove(Object key, Object value) {
if (key == null) {
throw new NullPointerException();
}
return value != null && replaceNode(key, null, value) != null;
}