都知道 HashMap 是线程不安全的。那应该怎么解决呢?除了 Collections 工具类实现(底层重要方法加上Synchronize关键字),就是本文的ConcurrentHashMap,采用了粒度更小的片段加锁方式。
1. 类的定义
- 虽然名字中也有 HashMap,但是并没有继承 HashMap。
- ConcurrentHashMap 继承 AbstractMap,实现 ConcurrentMap、Serializable,即表示是一个可序列化的 Map
public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
implements ConcurrentMap<K,V>, Serializable {}
1.1 先来看 ConcurrentHashMap 的构造函数
- ConcurrentHashMap 总共有 5 个构造函数
/* 空构造函数:使用默认容量为 16 */
public ConcurrentHashMap() {
}
/* initialCapacity:初始容量 */
public ConcurrentHashMap(int initialCapacity) {
/* 初始容量不能小于 0 */
if (initialCapacity < 0)
throw new IllegalArgumentException();
/* 若指定的初始容量 >= 最大容量的一半,使用最大容量MAXIMUM_CAPACITY
* 否则获取最靠近 (1.5倍初始容量 + 1)的 2的指数次幂的整数 */
/* 这里的1.5倍,我的理解是这样:若传入的初始容量为12,扩容因子为0.75
* 若只用 12 传入,则 cap 应为 16,一般情况下,我们初始一个容量,都会加入对应的元素,则元素个数到达12时会进行扩容
* 若使用 12 * 1.5 + 1 = 19,则 cap 应为 32,元素个数到达12时,不会进行扩容
* 至于为什么 HashMap 不这样使用,我也不知道 */
int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
MAXIMUM_CAPACITY :
tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
/* 设置 sizeCtl 为计算后的初始容量cap */
this.sizeCtl = cap;
}
/* 指定初始容量,扩容因子,初始化并发数为 1 */
public ConcurrentHashMap(int initialCapacity, float loadFactor) {
this(initialCapacity, loadFactor, 1);
}
/* concurrencyLevel: 并发数量,jdk1.8 有多少个桶就有多少个并发数 */
public ConcurrentHashMap(int initialCapacity,
float loadFactor, int concurrencyLevel) {
/* 加载因子 < 0 || 初始容量 < 0 || concurrencyLevel < = 0 则报参数错误 */
if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0)
throw new IllegalArgumentException();
/* 容量应该大于并发线程数,不然没有意义 */
if (initialCapacity < concurrencyLevel)
initialCapacity = concurrencyLevel;
/* 使用传入的初始容量initialCapacity /扩容因子loadFactor + 1 计算大致的元素个数 */
long size = (long)(1.0 + (long)initialCapacity / loadFactor);
/* 元素个数 >= 最大容量,则使用最大容量值,否则使用最接近 size 的 2 的指数次幂 */
int cap = (size >= (long)MAXIMUM_CAPACITY) ?
MAXIMUM_CAPACITY : tableSizeFor((int)size);
this.sizeCtl = cap;
}
/* 初始化集合 map */
public ConcurrentHashMap(Map<? extends K, ? extends V> m) {
/* 使用默认容量 */
this.sizeCtl = DEFAULT_CAPACITY;
/* 添加集合m 的作用元素,后面详讲 */
putAll(m);
}
- 小总结:对比HashMap,ConcurrentHashMap 构造函数中多了一个属性 sizeCtl,有什么作用呢? 接着往下看。
1.2 ConcurrentHashMap 的属性
- static 变量
/* 万年不变的版本号 */
private static final long serialVersionUID = 7249069246763182397L;
/* 数组最大容量 */
private static final int MAXIMUM_CAPACITY = 1 << 30;
/* 默认初始容量,必须为2 的指数次幂,不超过最大容量 1 << 30 */
private static final int DEFAULT_CAPACITY = 16;
/* 最大数组长度 */
static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/* 默认并发数 */
private static final int DEFAULT_CONCURRENCY_LEVEL = 16;
/* 默认扩容因子 */
private static final float LOAD_FACTOR = 0.75f;
/* 默认树化元素个数 */
static final int TREEIFY_THRESHOLD = 8;
/* 退化成链元素个数 */
static final int UNTREEIFY_THRESHOLD = 6;
/* 最小树化容量 */
static final int MIN_TREEIFY_CAPACITY = 64;
/* 扩容时数据前移的步长,默认最小为16 */
private static final int MIN_TRANSFER_STRIDE = 16;
/* 扩容位数标识,主要用于扩容时生成一个巨大负数使用(细品第32位的标志位与 16位为1左移16位) */
private static int RESIZE_STAMP_BITS = 16;
/* 最大并发线程数 65535 */
private static final int MAX_RESIZERS = (1 << (32 - RESIZE_STAMP_BITS)) - 1;
/* 扩容位数标识剩下的位数 */
private static final int RESIZE_STAMP_SHIFT = 32 - RESIZE_STAMP_BITS;
/* 节点标识 */
static final int MOVED = -1; // 节点正在扩容
static final int TREEBIN = -2; // 树节点
static final int RESERVED = -3; // 正在设置桶位首节点,与只有一个节点区分
static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash
/* 系统CPu数量 */
static final int NCPU = Runtime.getRuntime().availableProcessors();
/* 用于序列化兼容性 */
private static final ObjectStreamField[] serialPersistentFields = {
new ObjectStreamField("segments", Segment[].class),
new ObjectStreamField("segmentMask", Integer.TYPE),
new ObjectStreamField("segmentShift", Integer.TYPE)
};
// Unsafe mechanics
private static final sun.misc.Unsafe U;
private static final long SIZECTL;
private static final long TRANSFERINDEX;
private static final long BASECOUNT;
private static final long CELLSBUSY;
private static final long CELLVALUE;
private static final long ABASE;
private static final int ASHIFT;
static {
try {
U = sun.misc.Unsafe.getUnsafe();
Class<?> k = ConcurrentHashMap.class;
SIZECTL = U.objectFieldOffset
(k.getDeclaredField("sizeCtl"));
TRANSFERINDEX = U.objectFieldOffset
(k.getDeclaredField("transferIndex"));
BASECOUNT = U.objectFieldOffset
(k.getDeclaredField("baseCount"));
CELLSBUSY = U.objectFieldOffset
(k.getDeclaredField("cellsBusy"));
Class<?> ck = CounterCell.class;
CELLVALUE = U.objectFieldOffset
(ck.getDeclaredField("value"));
Class<?> ak = Node[].class;
ABASE = U.arrayBaseOffset(ak);
int scale = U.arrayIndexScale(ak);
if ((scale & (scale - 1)) != 0)
throw new Error("data type scale not a power of two");
ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
} catch (Exception e) {
throw new Error(e);
}
}
- 实例变量
/* 存储数据的底层数组 */
transient volatile Node<K,V>[] table;
/* 扩容用的新数组,扩容完成后置为null,默认为null */
private transient volatile Node<K,V>[] nextTable;
/* 元素个数的基础计数,加上counterCells数组所有元素的value值总和 即为所有元素个数 */
private transient volatile long baseCount;
/* 扩容指数:为0 是默认值,为负数则正在扩容,为正数代表临界值(阈值) */
private transient volatile int sizeCtl;
/* 标识扩容时还未被分配迁移数据的个数 */
private transient volatile int transferIndex;
/* 用于判断counterCells是否正在被使用,0为可使用,1为当前有线程正在使用 */
private transient volatile int cellsBusy;
/* 并发情况下,使用该数组进行count联合计数,减少baseCount的计数压力,提高效率 */
private transient volatile CounterCell[] counterCells;
/* key,value,entry 集合 */
private transient KeySetView<K,V> keySet;
private transient ValuesView<K,V> values;
private transient EntrySetView<K,V> entrySet;
- 总结:相比 HashMap,ConcurrentHashMap 具有更多的属性,看着也迷迷糊糊。先了解大概印象,等摸清全部脉络,再来回顾。
1.3 内部类
- ConcurrentHashMap 有几十个内部类,慢慢来,总会搞明白的。
1.3.1 Node
- 与 HashMap 的不同,就是 val 与 next 增加了 volatile 修饰符,修改具有可见性。
- 有ForwardingNode、ReservationNode、TreeNode和TreeBin四个子类。
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
volatile V val;
volatile Node<K,V> next;
/* 全参构造函数 */
Node(int hash, K key, V val, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.val = val;
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return val; }
/* 重写 hashCode */
public final int hashCode() { return key.hashCode() ^ val.hashCode(); }
public final String toString(){ return key + "=" + val; }
/* 不能修改 value 值,否则报错 UnsupportedOperationException */
public final V setValue(V value) {
throw new UnsupportedOperationException();
}
/* 相同节点判断 */
public final boolean equals(Object o) {
Object k, v, u; Map.Entry<?,?> e;
/* 是否属于Map.Entry 的实例
* key 值是否为空, value 值是否为空
* key 值是否相等, value 值是否相等
* */
return ((o instanceof Map.Entry) &&
(k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
(v = e.getValue()) != null &&
(k == key || k.equals(key)) &&
(v == (u = val) || v.equals(u)));
}
/* 查找 k 对应的节点 */
Node<K,V> find(int h, Object k) {
/* 从当前节点e 开始遍历,找到返回节点e,找不到返回 null */
Node<K,V> e = this;
if (k != null) {
do {
K ek;
if (e.hash == h &&
((ek = e.key) == k || (ek != null && k.equals(ek))))
return e;
} while ((e = e.next) != null);
}
return null;
}
}
1.3.2 Segment<K,V>
- Segment 继承了 ReentrantLock,即具有lock的所有特性,只有一个构造函数,指定扩容因子
static class Segment<K,V> extends ReentrantLock implements Serializable {
private static final long serialVersionUID = 2249069246763182397L;
final float loadFactor;
Segment(float lf) { this.loadFactor = lf; }
}
1.3.3 ForwardingNode
- ForwardingNode 继承 Node,扩容时使用,标志当前节点正在移位
static final class ForwardingNode<K,V> extends Node<K,V> {
final Node<K,V>[] nextTable;
/* 指定 MOVED 为当前节点的 Hash,标志正在移位 */
ForwardingNode(Node<K,V>[] tab) {
super(MOVED, null, null, null);
this.nextTable = tab;
}
/* 查找 k 节点 */
Node<K,V> find(int h, Object k) {
// loop to avoid arbitrarily deep recursion on forwarding nodes
outer: for (Node<K,V>[] tab = nextTable;;) {
Node<K,V> e; int n;
/* 找不到对应的节点,返回 null */
if (k == null || tab == null || (n = tab.length) == 0 ||
(e = tabAt(tab, (n - 1) & h)) == null) // 已经进行 e 的赋值
return null;
for (;;) {
int eh; K ek;
/* 找到对应的节点,直接返回 */
if ((eh = e.hash) == h &&
((ek = e.key) == k || (ek != null && k.equals(ek))))
return e;
/* e.hash < 0 */
if (eh < 0) {
/* 判断当前节点是否为 ForwardingNode */
if (e instanceof ForwardingNode) {
tab = ((ForwardingNode<K,V>)e).nextTable;
continue outer;
}
else
return e.find(h, k);
}
if ((e = e.next) == null)
return null;
}
}
}
}
1.3.4 ReservationNode
- 用于CAS设置桶位首节点时使用,抢到权限后首节点会设置成Node,即ReservationNode 只有过渡作用
static final class ReservationNode<K,V> extends Node<K,V> {
ReservationNode() {
super(RESERVED, null, null, null);
}
/* 直接返回 null,无节点可查找 */
Node<K,V> find(int h, Object k) {
return null;
}
}
1.3.5 CounterCell
- 主要用于对baseCount的计数
@sun.misc.Contended static final class CounterCell {
volatile long value;
CounterCell(long x) { value = x; }
}
1.3.6 TreeNode<K,V>
- 树节点,继承 Node,
static final class TreeNode<K,V> extends Node<K,V> {
TreeNode<K,V> parent; // 父节点
TreeNode<K,V> left; // 左节点
TreeNode<K,V> right; // 右节点
TreeNode<K,V> prev; // 前置节点
boolean red; // 节点颜色
/* 构造函数:指定属性 */
TreeNode(int hash, K key, V val, Node<K,V> next,
TreeNode<K,V> parent) {
super(hash, key, val, next);
this.parent = parent;
}
/* 查找节点,底层调用 findTreeNode */
Node<K,V> find(int h, Object k) {
return findTreeNode(h, k, null);
}
/* 查找树节点 */
final TreeNode<K,V> findTreeNode(int h, Object k, Class<?> kc) {
/* key 为 null 直接返回 null */
if (k != null) {
/* 设置 p 为当前节点 */
TreeNode<K,V> p = this;
do {
/* ph: p.hash, pk: p.key, q: 中转节点 */
int ph, dir; K pk; TreeNode<K,V> q;
/* 获取左右节点 */
TreeNode<K,V> pl = p.left, pr = p.right;
if ((ph = p.hash) > h)
p = pl; // 往左找
else if (ph < h)
p = pr; // 往右找
/* hash 相等,判断 key 是否相等 */
else if ((pk = p.key) == k || (pk != null && k.equals(pk)))
return p;
/* hash 相等,key 不相等 */
else if (pl == null)
p = pr; // 左节点为空,往右找
else if (pr == null)
p = pl; // 右节点为空,往左找
/* 左右不为空,使用 comparableClass 比较出大小*/
else if ((kc != null ||
(kc = comparableClassFor(k)) != null) &&
(dir = compareComparables(kc, k, pk)) != 0)
p = (dir < 0) ? pl : pr;
/* 实在比较不出,先往右节点递归 */
else if ((q = pr.findTreeNode(h, k, kc)) != null)
return q;
else
p = pl; // 右节点找不到往左
} while (p != null);
}
return null;
}
}
1.3.7 TreeBin<K,V>
- 封装TreeNode节点, 继承 Node,tab[i] 位置存放的就是 TreeBin
- 对照 探索红黑树插入和删除的平衡原理,可更清晰的看懂关于操作红黑树的源码
static final class TreeBin<K,V> extends Node<K,V> {
TreeNode<K,V> root; // root 节点
volatile TreeNode<K,V> first; // 首节点
volatile Thread waiter; // 等待线程
volatile int lockState; // 锁状态
// values for lockState
static final int WRITER = 1; // 持有写锁
static final int WAITER = 2; // 等待写锁
static final int READER = 4; // 读锁
/* 用于hash值相等,但使用 compareComparables 也比较不出 key 大小的情况 */
static int tieBreakOrder(Object a, Object b) {
int d;
/* 若 className 比较不出大小,则使用 identityHashCode */
if (a == null || b == null ||
(d = a.getClass().getName().
compareTo(b.getClass().getName())) == 0)
d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
-1 : 1);
return d;
}
/* 构造函数:传入一个 树节点TreeNode */
TreeBin(TreeNode<K,V> b) {
super(TREEBIN, null, null, null); // Node 构造函数
this.first = b; // 设置 b 为首节点
TreeNode<K,V> r = null; // 初始化根节点
for (TreeNode<K,V> x = b, next; x != null; x = next) {
next = (TreeNode<K,V>)x.next; // 获取 next 节点
x.left = x.right = null;
/* 初始化根节点 */
if (r == null) {
x.parent = null;
x.red = false;
r = x;
}
else {
K k = x.key;
int h = x.hash;
Class<?> kc = null;
/* p 为 x 的父节点 */
for (TreeNode<K,V> p = r;;) {
int dir, ph;
K pk = p.key;
/* 判断节点 x 应该存放的位置 */
if ((ph = p.hash) > h)
dir = -1;
else if (ph < h)
dir = 1;
else if ((kc == null &&
(kc = comparableClassFor(k)) == null) ||
(dir = compareComparables(kc, k, pk)) == 0)
dir = tieBreakOrder(k, pk);
TreeNode<K,V> xp = p;
/* 根据 dir 判断 x 为 p 的左节点还是右节点 */
if ((p = (dir <= 0) ? p.left : p.right) == null) {
x.parent = xp;
if (dir <= 0)
xp.left = x;
else
xp.right = x;
/* 插入平衡操作 */
r = balanceInsertion(r, x);
break;
}
}
}
}
this.root = r; // 设置 根节点
assert checkInvariants(root);
}
/* 根节点的加锁,锁的是当前桶位 */
private final void lockRoot() {
if (!U.compareAndSwapInt(this, LOCKSTATE, 0, WRITER))
contendedLock(); // CAS失败
}
/* 根节点解锁 */
private final void unlockRoot() {
lockState = 0;
}
/* 阻塞等待 root 锁 */
private final void contendedLock() {
boolean waiting = false;
for (int s;;) {
/* 没有线程持有写锁时,尝试获取写锁 */
if (((s = lockState) & ~WAITER) == 0) {
if (U.compareAndSwapInt(this, LOCKSTATE, s, WRITER)) {
/* 拿到锁后将等待线程清空(等待线程是它自己)*/
if (waiting)
waiter = null;
return;
}
}
/* 有线程持有写锁且本线程状态不为WAITER时 */
else if ((s & WAITER) == 0) {
/* 尝试占有waiting线程 */
if (U.compareAndSwapInt(this, LOCKSTATE, s, s | WAITER)) {
waiting = true;
waiter = Thread.currentThread();
}
}
/* 有线程持有写锁且本线程状态为WAITER时,堵塞自己 */
else if (waiting)
LockSupport.park(this);
}
}
/* 寻找节点的方法 */
final Node<K,V> find(int h, Object k) {
/* key 为null, 直接返回null */
if (k != null) {
/* 首节点开始比较 */
for (Node<K,V> e = first; e != null; ) {
int s; K ek;
/* 写锁被持有时使用链表的方法遍历 */
if (((s = lockState) & (WAITER|WRITER)) != 0) {
/* 比较key 是否相等 */
if (e.hash == h &&
((ek = e.key) == k || (ek != null && k.equals(ek))))
return e;
e = e.next;
}
/* 写锁没被持有时,持有一个读锁,用红黑树的方法遍历 */
else if (U.compareAndSwapInt(this, LOCKSTATE, s,
s + READER)) {
TreeNode<K,V> r, p;
try {
p = ((r = root) == null ? null :
r.findTreeNode(h, k, null));
} finally {
Thread w;
/* 当前线程持有最后一个读锁的时候通知waiter线程获取写锁 */
/* 为什么剩下一个读锁时唤醒等待线程,我也不知道 */
if (U.getAndAddInt(this, LOCKSTATE, -READER) ==
(READER|WAITER) && (w = waiter) != null)
LockSupport.unpark(w);
}
return p;
}
}
}
return null;
}
/* 添加节点 */
final TreeNode<K,V> putTreeVal(int h, K k, V v) {
Class<?> kc = null;
boolean searched = false;
for (TreeNode<K,V> p = root;;) {
int dir, ph; K pk;
/* root 为空,直接添加 */
if (p == null) {
first = root = new TreeNode<K,V>(h, k, v, null, null);
break;
}
/* 判断 p 节点插入的位置 */
else if ((ph = p.hash) > h)
dir = -1;
else if (ph < h)
dir = 1;
/* key 相等则返回 p */
else if ((pk = p.key) == k || (pk != null && k.equals(pk)))
return p;
/* hash相等,key不相等 */
else if ((kc == null &&
(kc = comparableClassFor(k)) == null) ||
(dir = compareComparables(kc, k, pk)) == 0) {
/* searched 表示为true遍历过所有元素且没有与k相等的key */
if (!searched) {
TreeNode<K,V> q, ch;
searched = true;
/* 先往左递归,再往右递归 */
if (((ch = p.left) != null &&
(q = ch.findTreeNode(h, k, kc)) != null) ||
((ch = p.right) != null &&
(q = ch.findTreeNode(h, k, kc)) != null))
return q;
}
dir = tieBreakOrder(k, pk); // comparableClass 比较不出key大小时执行
}
TreeNode<K,V> xp = p;
/* 根据 dir 判断左右节点,若对应的子节点为null,则已找到插入位置,否则继续循环 */
if ((p = (dir <= 0) ? p.left : p.right) == null) {
TreeNode<K,V> x, f = first;
/* 将插入的节点设置为 first 节点 */
first = x = new TreeNode<K,V>(h, k, v, f, xp);
if (f != null)
f.prev = x;
/* 根据dir 判断左右节点*/
if (dir <= 0)
xp.left = x;
else
xp.right = x;
/* 父节点为黑色,直接插入 */
if (!xp.red)
x.red = true;
else {
/* 锁住根节点,进行红黑树插入平衡 */
lockRoot();
try {
root = balanceInsertion(root, x);
} finally {
unlockRoot();
}
}
break;
}
}
assert checkInvariants(root);
return null;
}
/* 删除 removeTreeNode 节点 */
final boolean removeTreeNode(TreeNode<K,V> p) {
TreeNode<K,V> next = (TreeNode<K,V>)p.next; // 后继节点
TreeNode<K,V> pred = p.prev; // 前置节点
TreeNode<K,V> r, rl;
/* 处理链表的节点指针,删除 p */
if (pred == null)
first = next;
else
pred.next = next;
if (next != null)
next.prev = pred;
/* 没有节点了,直接返回 */
if (first == null) {
root = null;
return true;
}
/* 个数太少:root 为空 || root.right 为空 || root.left为空 || root.left.left 为空 */
if ((r = root) == null || r.right == null || // too small
(rl = r.left) == null || rl.left == null)
return true;
/* 锁住根节点 */
lockRoot();
try {
TreeNode<K,V> replacement; // 替代节点
TreeNode<K,V> pl = p.left; // p 的左节点
TreeNode<K,V> pr = p.right; // p 的右节点
/* 左右节点都不为空 */
if (pl != null && pr != null) {
TreeNode<K,V> s = pr, sl; // s 为 p.right
while ((sl = s.left) != null) // 获得后继节点,右子树的最左子节点
s = sl;
/* 交换 后继节点s 与 删除节点p 的颜色 */
boolean c = s.red; s.red = p.red; p.red = c;
TreeNode<K,V> sr = s.right;
TreeNode<K,V> pp = p.parent;
/* 可自行画图,交换 s,p 节点需要更换哪些指针,对照代码看更清楚(parent,left,right) */
/* p.right 为后继节点,即 p.right 没有左子节点 */
if (s == pr) {
/* 交换 s,p 的指针 */
p.parent = s;
s.right = p;
}
else {
/* 交换 s,p 的指针 */
TreeNode<K,V> sp = s.parent;
if ((p.parent = sp) != null) {
if (s == sp.left)
sp.left = p;
else
sp.right = p;
}
if ((s.right = pr) != null)
pr.parent = s;
}
p.left = null; // s没有左子节点
if ((p.right = sr) != null)
sr.parent = p;
if ((s.left = pl) != null)
pl.parent = s;
if ((s.parent = pp) == null)
r = s;
else if (p == pp.left)
pp.left = s;
else
pp.right = s;
/* 若右节点存在,由于删除的是替代节点,变成只有右子节点的情况 */
if (sr != null)
replacement = sr;
else
replacement = p;
}
else if (pl != null)
replacement = pl; // 只有左子节点
else if (pr != null)
replacement = pr; // 只有右子节点
else
replacement = p; // 没有子节点,亲自上阵
/* 若具有替代节点,先删除节点p */
if (replacement != p) {
TreeNode<K,V> pp = replacement.parent = p.parent;
if (pp == null)
r = replacement;
else if (p == pp.left)
pp.left = replacement;
else
pp.right = replacement;
p.left = p.right = p.parent = null;
}
/* 若删除的不是红色节点,需要进行红黑树删除平衡操作 */
root = (p.red) ? r : balanceDeletion(r, replacement);
/* 由于平衡操作不会删除节点,亲自上的情况需要平衡后进行节点删除 */
if (p == replacement) {
TreeNode<K,V> pp;
if ((pp = p.parent) != null) {
if (p == pp.left)
pp.left = null;
else if (p == pp.right)
pp.right = null;
p.parent = null;
}
}
} finally {
unlockRoot();
}
/* 检测红黑树状态 */
assert checkInvariants(root);
return false;
}
/* ---------------红黑树平衡操作-------------- */
/* root: 根节点 , x: 新插入的节点 */
static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
TreeNode<K,V> x) {
/* 插入的节点都为红色节点,不然就没有红黑树了 */
x.red = true;
/* xp: x 的父亲节点, xpp: x 的爷爷节点, xppl: x 的爷爷节点的左节点, xppr: x 的爷爷节点的右节点 */
for (TreeNode<K,V> xp, xpp, xppl, xppr;;) {
/* 情景1:红黑树为空树,设置 x 节点为根节点,改为黑色 */
if ((xp = x.parent) == null) {
x.red = false;
return x;
}
/* 情景3:父节点为黑色,直接赋值,不用操作 || 爷爷节点为空(其实就是父节点为 root , 就是为了赋值) */
else if (!xp.red || (xpp = xp.parent) == null)
return root;
/* 情景4.2:父节点为祖父节点的左节点 */
if (xp == (xppl = xpp.left)) {
/* 情景4.1:叔叔节点(右节点)不为空且为红色节点 */
if ((xppr = xpp.right) != null && xppr.red) {
/* 叔叔节点、父亲节点设置为黑色,爷爷节点设置为红色,x 设置为爷爷节点,上层传递 */
xppr.red = false;
xp.red = false;
xpp.red = true;
x = xpp;
}
else {
/* 情景4.2.2 插入节点是其父节点的右子节点 */
if (x == xp.right) {
root = rotateLeft(root, x = xp);
xpp = (xp = x.parent) == null ? null : xp.parent;
}
/* 情景4.2.1 插入节点是其父节点的左子节点 */
if (xp != null) {
xp.red = false;
if (xpp != null) {
xpp.red = true;
root = rotateRight(root, xpp);
}
}
}
}
/* 情景4.3:父节点为祖父节点的右节点 */
else {
/* 情景4.1:叔叔节点(右节点)不为空且为红色节点 */
if (xppl != null && xppl.red) {
/* 父亲节点、叔叔节点变为黑色,爷爷节点变为红色,x = xpp 将红色节点向上抛 */
xppl.red = false;
xp.red = false;
xpp.red = true;
x = xpp;
}
else {
/* 情景4.3.2 插入节点是其父节点的左子节点 */
if (x == xp.left) {
root = rotateRight(root, x = xp);
xpp = (xp = x.parent) == null ? null : xp.parent;
}
/* 情景4.3.1 插入节点是其父节点的右子节点 */
if (xp != null) {
/* 父节点设置为黑色 */
xp.red = false;
if (xpp != null) {
/* 爷爷节点设置为红色,并进行左旋 */
xpp.red = true;
root = rotateLeft(root, xpp);
}
}
}
}
}
}
/* root: 根节点, x:删除的节点 */
static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
TreeNode<K,V> x) {
for (TreeNode<K,V> xp, xpl, xpr;;) {
/* x 为null || x 为根节点时退出 */
if (x == null || x == root)
return root;
/* 删除情况2,只有一个子节点且删除的节点为 root */
/* 出现的情况是 root 有一个子结点,删除root */
else if ((xp = x.parent) == null) {
x.red = false;
return x;
}
/* 情景1:节点为红色直接删除 */
else if (x.red) {
x.red = false;
return root;
}
/* 情景2.1:替换节点是左节点 */
else if ((xpl = xp.left) == x) {
/* 情景2.1.1:替换节点的兄弟节点为红色 */
if ((xpr = xp.right) != null && xpr.red) {
xpr.red = false;
xp.red = true;
root = rotateLeft(root, xp);
xpr = (xp = x.parent) == null ? null : xp.right;
}
/* 情景2.1.2.3: 替换结点的兄弟结点的子结点都为黑结点,兄弟节点为null,无需变红
可以看作是排除没有子节点的情况 */
if (xpr == null)
x = xp;
else {
TreeNode<K,V> sl = xpr.left, sr = xpr.right;
/* 情景2.1.2.3: 替换结点的兄弟结点的子结点都为黑结点 */
if ((sr == null || !sr.red) &&
(sl == null || !sl.red)) {
xpr.red = true;
x = xp;
}
else {
/* 情景2.1.2.2: 替换结点的兄弟结点的右子结点是黑结点,左子结点为红色节点 */
if (sr == null || !sr.red) {
if (sl != null)
sl.red = false;
xpr.red = true;
root = rotateRight(root, xpr);
/* 旋转后更换兄弟节点 */
xpr = (xp = x.parent) == null ?
null : xp.right;
}
/* 情景2.1.2.1: 替换结点的兄弟结点的右子结点是红结点,左子结点任意颜色 */
if (xpr != null) {
xpr.red = (xp == null) ? false : xp.red;
if ((sr = xpr.right) != null)
sr.red = false;
}
if (xp != null) {
xp.red = false;
root = rotateLeft(root, xp);
}
/* 到这里,删除平衡操作已完成,将 x == root 为了下一次进入循环直接退出,我也不知道为什么不直接 return root */
x = root;
}
}
}
/* 情景2.2:替换节点是右节点 */
else {
/* 情景2.2.1: 替换结点的兄弟结点是红结点 */
if (xpl != null && xpl.red) {
xpl.red = false;
xp.red = true;
root = rotateRight(root, xp);
xpl = (xp = x.parent) == null ? null : xp.left;
}
/* 情景2.2.2.3: 替换结点的兄弟结点的子结点都为黑结点(NIL),兄弟节点为null,无需变红
可以看作是排除没有子节点的情况 */
if (xpl == null)
x = xp;
else {
/* 情景2.2.2.3: 替换结点的兄弟结点的子结点都为黑结点 */
TreeNode<K,V> sl = xpl.left, sr = xpl.right;
if ((sl == null || !sl.red) &&
(sr == null || !sr.red)) {
xpl.red = true;
x = xp;
}
else {
/* 情景2.2.2.2: 替换结点的兄弟结点的左子结点是黑结点,右子结点为红色节点 */
if (sl == null || !sl.red) {
if (sr != null)
sr.red = false;
xpl.red = true;
root = rotateLeft(root, xpl);
/* 旋转后更换兄弟节点 */
xpl = (xp = x.parent) == null ?
null : xp.left;
}
/* 情景2.2.2.1: 替换结点的兄弟结点的左子结点是红结点,右子结点任意颜色 */
if (xpl != null) {
xpl.red = (xp == null) ? false : xp.red;
if ((sl = xpl.left) != null)
sl.red = false;
}
if (xp != null) {
xp.red = false;
root = rotateRight(root, xp);
}
/* 到这里,删除平衡操作已完成,将 x == root 为了下一次进入循环直接退出,我也不知道为什么不直接 return root */
x = root;
}
}
}
}
}
/* t: 传入的某个节点 */
static <K,V> boolean checkInvariants(TreeNode<K,V> t) {
/* tp: 根节点的父节点,tl: 根节点的左节点, tr: 根节点的右节点 */
TreeNode<K,V> tp = t.parent, tl = t.left, tr = t.right,
/* tb: 根节点的前置节点,tn: 根节点后置节点 */
tb = t.prev, tn = (TreeNode<K,V>)t.next;
/* 出现以下任何一种情况,则表示树结构或者链结构不正确 */
/* 1. 前驱节点存在,但是前驱节点的后置节点不为 t */
if (tb != null && tb.next != t)
return false;
/* 2. 后置节点存在,但是后置节点的前驱节点不为 t */
if (tn != null && tn.prev != t)
return false;
/* 父节点存在,但是 t 不是父节点的左子节点 or 右子节点 */
if (tp != null && t != tp.left && t != tp.right)
return false;
/* 左节点存在,但左节点的父节点不是 t || 左节点的hash值 > t的hash值 */
if (tl != null && (tl.parent != t || tl.hash > t.hash))
return false;
/* 右节点存在,但右节点的父节点不是 t || 右节点的hash值 < t的hash值 */
if (tr != null && (tr.parent != t || tr.hash < t.hash))
return false;
/* 当前节点为红色 且 子节点也为红色 */
if (t.red && tl != null && tl.red && tr != null && tr.red)
return false;
/* 递归验证左子树 */
if (tl != null && !checkInvariants(tl))
return false;
/* 递归验证右子树 */
if (tr != null && !checkInvariants(tr))
return false;
/* 都正确返回 true */
return true;
}
private static final sun.misc.Unsafe U;
private static final long LOCKSTATE;
static {
try {
U = sun.misc.Unsafe.getUnsafe();
Class<?> k = TreeBin.class;
LOCKSTATE = U.objectFieldOffset
(k.getDeclaredField("lockState"));
} catch (Exception e) {
throw new Error(e);
}
}
}