【JUC源码解析】ConcurrentHashMap

简介

支持并发的哈希表。其中包括红黑树,扩容,分槽计数等知识点。

源码分析

常量

 1     private static final int MAXIMUM_CAPACITY = 1 << 30; // 最大容量
 2     private static final int DEFAULT_CAPACITY = 16; // 默认容量,2^n
 3     static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // 可能的最大数组大小
 4     private static final int DEFAULT_CONCURRENCY_LEVEL = 16; // 默认并发级别
 5     private static final float LOAD_FACTOR = 0.75f; // 负载因子
 6     static final int TREEIFY_THRESHOLD = 8; // 链表转树阈值,链表长度超过8时转成红黑树
 7     static final int UNTREEIFY_THRESHOLD = 6; // 树转链表阈值,树的元素小于等于6时转成链表
 8     static final int MIN_TREEIFY_CAPACITY = 64; // 最小转树容量
 9     private static final int MIN_TRANSFER_STRIDE = 16; // 最小转换步长
10     private static int RESIZE_STAMP_BITS = 16; // 调整大小标记比特数
11     private static final int MAX_RESIZERS = (1 << (32 - RESIZE_STAMP_BITS)) - 1; // 最大的可以调整大小的线程数
12     private static final int RESIZE_STAMP_SHIFT = 32 - RESIZE_STAMP_BITS; // 调整大小的标记移位
13 
14     static final int MOVED = -1; // 转移结点hash值
15     static final int TREEBIN = -2; // 树根结点hash值
16     static final int RESERVED = -3; // 保留hash
17     static final int HASH_BITS = 0x7fffffff; // 正常结点hash的有效位
18 
19     static final int NCPU = Runtime.getRuntime().availableProcessors(); // CPU的个数

属性

1     transient volatile Node<K, V>[] table; // hash表,第一次插入数据时初始化,大小为2^n
2     private transient volatile Node<K, V>[] nextTable; // 扩容后的数组
3     private transient volatile long baseCount; // 基本大小
4     private transient volatile int sizeCtl; // 0:默认,-1:table正在初始化,-N:表示有N-1个线程正在进行扩容操作,此描述不准确,须结合resizeStamp推断;其他:1.未初始化,表示初始化大小;2.已经初始化,表示table的容量,默认为table大小的0.75倍,0.75n = 3n/4 = (1 - 1/4)n = n - n/4 = (n - (n >>> 2))
5     private transient volatile int transferIndex; // 转换索引,扩容时,下一个表索引
6     private transient volatile int cellsBusy; // 自旋锁(通过CAS锁定)
7     private transient volatile CounterCell[] counterCells; // 大小为2^n

构造方法

 1     public ConcurrentHashMap() { // 无参构造
 2     }
 3 
 4     public ConcurrentHashMap(int initialCapacity) { // 构造方法
 5         if (initialCapacity < 0) // 参数校验
 6             throw new IllegalArgumentException();
 7         // cap乘以负载因子loadFactor应该大于等于initialCapcity,即是,cap >= initialCapcity /
 8         // loadFactor,这里是loadFactor = 0.75
 9         // 即是,cap >= initialCapcity * 4/3 = initialCapcity + (1/3) *
10         // initialCapcity
11         // 构造方法里,是根据initialCapacity + (initialCapacity >>> 1) + 1确立的cap,
12         // initialCapacity >>> 1 = initialCapacity * (1/2) > initialCapacity *
13         // (1/3)满足要求
14         // 后面还有+1,应该是避免为0吧,毕竟要有元素
15         // 最后代入到tableSizeFor(int)方法里,使得最后的cap为2的n次方,如果输入的是10,最后的结果是16,大于且最贴近输入值
16         int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY
17                 : tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
18         this.sizeCtl = cap;
19     }
20 
21     public ConcurrentHashMap(Map<? extends K, ? extends V> m) { // 构造方法
22         this.sizeCtl = DEFAULT_CAPACITY;
23         putAll(m);
24     }
25 
26     public ConcurrentHashMap(int initialCapacity, float loadFactor) { // 构造方法
27         this(initialCapacity, loadFactor, 1);
28     }
29 
30     public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) { // 构造方法
31         if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0) // 参数校验
32             throw new IllegalArgumentException();
33         if (initialCapacity < concurrencyLevel)
34             initialCapacity = concurrencyLevel; // 不小于并发级别
35         long size = (long) (1.0 + (long) initialCapacity / loadFactor); // 同上
36         int cap = (size >= (long) MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : tableSizeFor((int) size);
37         this.sizeCtl = cap;
38     }

数据结构

Node

继承关系

1 static class Node<K, V> implements Map.Entry<K, V> {}

属性

1         final int hash; // hash值
2         final K key; //
3         volatile V val; //
4         volatile Node<K, V> next; // 指向下一个结点

构造方法

1         Node(int hash, K key, V val, Node<K, V> next) { // 构造方法
2             this.hash = hash;
3             this.key = key;
4             this.val = val;
5             this.next = next;
6         }

find方法

 1         Node<K, V> find(int h, Object k) { // 根据hash值和键查找结点
 2             Node<K, V> e = this; // 指向当前结点
 3             if (k != null) { // 键不为空
 4                 do {
 5                     K ek;
 6                     if (e.hash == h && ((ek = e.key) == k || (ek != null && k.equals(ek)))) // hash值不同,直接比较下一个结点;否则,比较其地址或内容是否相等
 7                         return e;
 8                 } while ((e = e.next) != null);
 9             }
10             return null;
11         }

TreeNode

继承关系

1     static final class TreeNode<K, V> extends Node<K, V> {

属性

1         TreeNode<K, V> parent; // 父结点
2         TreeNode<K, V> left; // 左子结点
3         TreeNode<K, V> right; // 又子结点
4         TreeNode<K, V> prev; // 前一个结点
5         boolean red; // 是否为红色结点

构造方法

1         TreeNode(int hash, K key, V val, Node<K, V> next, TreeNode<K, V> parent) { // 构造方法
2             super(hash, key, val, next);
3             this.parent = parent;
4         }

find方法

1         Node<K, V> find(int h, Object k) { // 查找
2             return findTreeNode(h, k, null);
3         }

findTreeNode方法

 1         final TreeNode<K, V> findTreeNode(int h, Object k, Class<?> kc) { // 查找结点
 2             if (k != null) { // k若为空,直接返回null
 3                 TreeNode<K, V> p = this; // 当前结点
 4                 do {
 5                     int ph, dir; // p的hash值,k与p的key的compare值
 6                     K pk; // p的key
 7                     TreeNode<K, V> q;
 8                     TreeNode<K, V> pl = p.left, pr = p.right; // p的左子结点,p的右子结点
 9                     if ((ph = p.hash) > h) // 如果当前结点的hash值大于h,说明目标结点在左子树
10                         p = pl; // 令p指向左子结点
11                     else if (ph < h) // 如果当前结点的hash值小于h,说明目标结点在右子树
12                         p = pr; // 令p指向右子结点
13                     else if ((pk = p.key) == k || (pk != null && k.equals(pk))) // 如果当前结点就是目标结点
14                         return p; // 直接返回
15                     else if (pl == null) // 如果ph ==
16                                             // h,但是当前结点不是目标结点,则查看左子结点是否存在,不存在则指向右子结点
17                         p = pr;
18                     else if (pr == null) // 如果左子结点存在,那么查看右子结点是否存在,不存在则指向左子结点
19                         p = pl;
20                     else if ((kc != null || (kc = comparableClassFor(k)) != null) // 如果左右子结点都存在,并且k的Class不为空,则比较k的值顺序
21                             && (dir = compareComparables(kc, k, pk)) != 0)
22                         p = (dir < 0) ? pl : pr; // 目标结点小于当前结点,则指向左子结点,否则指向右子结点
23                     else if ((q = pr.findTreeNode(h, k, kc)) != null) // 如果以上条件不满足,则递归查找右子树
24                         return q; // 找到则返回
25                     else // 最后,如果以上条件均不满足,由于已经递归查找了右子树,所以,p指向左子结点,循环查找
26                         p = pl;
27                 } while (p != null);
28             }
29             return null;
30         }
31     }

TreeBin

继承关系

1     static final class TreeBin<K, V> extends Node<K, V>{}

属性

1         TreeNode<K, V> root; // 红黑树根节点
2         volatile TreeNode<K, V> first; // 链表头结点
3         volatile Thread waiter; // 等待线程
4         volatile int lockState; // 锁状态
5         static final int WRITER = 1; // 001, 持有写锁
6         static final int WAITER = 2; // 010, 等待写锁
7         static final int READER = 4; // 100, 每获取读锁,增加此值

构造方法

 1         TreeBin(TreeNode<K, V> b) { // 继承Node, 链表转红黑树
 2             super(TREEBIN, null, null, null); // 调用父类的构造方法
 3             this.first = b; // 头结点引用指向给定结点
 4             TreeNode<K, V> r = null;
 5             for (TreeNode<K, V> x = b, next; x != null; x = next) { // 从头结点开始往后遍历
 6                 next = (TreeNode<K, V>) x.next; // 指向下一个结点
 7                 x.left = x.right = null;
 8                 if (r == null) { // 根结点
 9                     x.parent = null; // 根节点没有父节点
10                     x.red = false; // 红黑树根结点是黑色结点
11                     r = x;
12                 } else {
13                     K k = x.key;
14                     int h = x.hash;
15                     Class<?> kc = null;
16                     for (TreeNode<K, V> p = r;;) { // 从根据点遍历,寻找合适的位置,插入给定结点
17                         int dir, ph;
18                         K pk = p.key;
19                         if ((ph = p.hash) > h) // 给定结点的hash值小于当前结点的hash值,往左子树寻找
20                             dir = -1;
21                         else if (ph < h) // 否则, 给定结点的hash值大于当前结点的hash值,往右子树寻找
22                             dir = 1;
23                         else if ((kc == null && (kc = comparableClassFor(k)) == null)
24                                 || (dir = compareComparables(kc, k, pk)) == 0) // 如果hash值相等,则比较k值,用其Compare,如果还相等,则走tieBreakOrder方法
25                             dir = tieBreakOrder(k, pk);
26                         TreeNode<K, V> xp = p; // 暂存当前结点
27                         if ((p = (dir <= 0) ? p.left : p.right) == null) { // 根据dir的值选取左右子结点,子结点不为空,继续循环寻找
28                             x.parent = xp; // 已找到合适位置,作为当前结点的子结点
29                             if (dir <= 0) // 小于0,使其成为左子结点
30                                 xp.left = x;
31                             else // 否则,使其成为右子结点
32                                 xp.right = x;
33                             r = balanceInsertion(r, x); // 插入后,平衡红黑树,使之满足红黑树性质
34                             break; // 跳出
35                         }
36                     }
37                 }
38             }
39             this.root = r; // 根节点
40             assert checkInvariants(root); // 检查一致性,红黑树及链表性质
41         }

find

 1         final Node<K, V> find(int h, Object k) {
 2             if (k != null) { // 如果k为空,直接返回null
 3                 for (Node<K, V> e = first; e != null;) { // 从首结点开始
 4                     int s;
 5                     K ek;
 6                     if (((s = lockState) & (WAITER | WRITER)) != 0) { // 如果有线程持有写锁,或有写线程在等待写锁,不再加读锁,而是以链表方式查找
 7                         if (e.hash == h && ((ek = e.key) == k || (ek != null && k.equals(ek))))
 8                             return e;
 9                         e = e.next;
10                     } else if (U.compareAndSwapInt(this, LOCKSTATE, s, s + READER)) { // 否则,加读锁
11                         TreeNode<K, V> r, p;
12                         try {
13                             p = ((r = root) == null ? null : r.findTreeNode(h, k, null)); // 以红黑树方式查找
14                         } finally {
15                             Thread w;
16                             if (U.getAndAddInt(this, LOCKSTATE, -READER) == (READER | WAITER) && (w = waiter) != null) // 如果没有读线程了,并且有写线程在等待
17                                 LockSupport.unpark(w); // 唤醒阻塞的写线程
18                         }
19                         return p;
20                     }
21                 }
22             }
23             return null;
24         }

putTreeVal

 1         final TreeNode<K, V> putTreeVal(int h, K k, V v) {
 2             Class<?> kc = null;
 3             boolean searched = false; // 如果遇见当前结点和目标结点发生碰撞的情况,且compare方法比较也相同,在进行调用tieBreakOrder方法之前,先搜索左子树或右子树一次,之后再遇见这种情况,则不必再搜索,因为那一次已经都搜索过了
 4             for (TreeNode<K, V> p = root;;) { // 从根节点开始
 5                 int dir, ph;
 6                 K pk;
 7                 if (p == null) { // 如果根节点为空,则构建新结点,first和root都指向它
 8                     first = root = new TreeNode<K, V>(h, k, v, null, null);
 9                     break;
10                 } else if ((ph = p.hash) > h) // 比较当前结点和目标结点的hash值
11                     dir = -1; // 目前结点的hash值较小,则往左子树寻找
12                 else if (ph < h)
13                     dir = 1; // 否则,往右子树寻找
14                 else if ((pk = p.key) == k || (pk != null && k.equals(pk))) // 如果hash相等,则比较key,若相等,则直接返回当前结点
15                     return p; // 该结点的value值,则由调用方决定是否替换成新的value值
16                 else if ((kc == null && (kc = comparableClassFor(k)) == null)
17                         || (dir = compareComparables(kc, k, pk)) == 0) { // hash碰撞(hash值相等,但key值不等),则采用compare方法比较
18                     if (!searched) { // 如果kc为空,或者hash相等,key的Compare也相等,并且左子树或者右子树还没有搜索过,则搜索一次
19                         TreeNode<K, V> q, ch;
20                         searched = true;
21                         if (((ch = p.left) != null && (q = ch.findTreeNode(h, k, kc)) != null)
22                                 || ((ch = p.right) != null && (q = ch.findTreeNode(h, k, kc)) != null)) // 先搜索左子树,搜到则返回;否则搜索右子树,搜到则返回
23                             return q;
24                     }
25                     dir = tieBreakOrder(k, pk); // 如果hash相等,key的Compare也相等,才采用此方法比较,此刻,dir要么为1,要么为-1
26                 }
27 
28                 TreeNode<K, V> xp = p; // 记录当前结点
29                 if ((p = (dir <= 0) ? p.left : p.right) == null) { // 根据dir的值,选择左子树或右子树
30                     TreeNode<K, V> x, f = first; // 记录原首结点
31                     first = x = new TreeNode<K, V>(h, k, v, f, xp); // 新结点从头部插入(创建新结点,first指向该新结点)
32                     if (f != null)
33                         f.prev = x; // 老的头节点prev属性指向新结点
34                     if (dir <= 0)
35                         xp.left = x; // 更新新结点为当前结点的左子结点
36                     else
37                         xp.right = x; // 更新新结点为当前结点的右子结点
38                     if (!xp.red) // 如果当前结点是黑色结点,则直接插入结点(红色),满足红黑树性质
39                         x.red = true;
40                     else { // 否则,需要平衡红黑树(结合重新着色和旋转)
41                         lockRoot(); // 平衡过程中,结点直接的树结构会发生改变,影响读操作,因此需要加锁,使读操作采用链表的方式进行
42                         try {
43                             root = balanceInsertion(root, x); // 平衡插入
44                         } finally {
45                             unlockRoot(); // 解锁
46                         }
47                     }
48                     break;
49                 }
50             }
51             assert checkInvariants(root); // 检测一致性
52             return null;
53         }

removeTreeNode

 1         final boolean removeTreeNode(TreeNode<K, V> p) {
 2             TreeNode<K, V> next = (TreeNode<K, V>) p.next; // 下一个结点
 3             TreeNode<K, V> pred = p.prev; // 上一个结点,这是不带p玩的节奏啊
 4             TreeNode<K, V> r, rl;
 5             if (pred == null) // 如果p解释头结点
 6                 first = next; // next结点成为新的头节点
 7             else
 8                 pred.next = next; // 否则,上一个结点和下一个结点直接相连
 9             if (next != null)
10                 next.prev = pred; // 相连
11             if (first == null) { // 如果p是唯一结点,置空root,直接返回
12                 root = null;
13                 return true;
14             }
15             if ((r = root) == null || r.right == null || // 规模较小,转成链表
16                     (rl = r.left) == null || rl.left == null)
17                 return true;
18             lockRoot(); // 否则,采用红黑树的删除方式,且需要加锁,同样因为考虑会影响读操作
19             try {
20                 TreeNode<K, V> replacement; // 二叉树(红黑树也是二叉树)的删除,如果结点不是尾结点,则需要找到该结点的后继结点(未结点,可以直接删除)填补此位置
21                 TreeNode<K, V> pl = p.left; // 左结点
22                 TreeNode<K, V> pr = p.right; // 右结点
23                 if (pl != null && pr != null) { // 如果都不为空
24                     TreeNode<K, V> s = pr, sl;
25                     while ((sl = s.left) != null) // 寻找p的后继结点,从p的右子结点开始,一直递归查找其左子结点,直至其没有左子结点
26                         s = sl;
27                     boolean c = s.red; // 后继结点是否是红色结点
28                     s.red = p.red;
29                     p.red = c; // p结点与其后继结点交换颜色
30                     TreeNode<K, V> sr = s.right; // 后继结点的右子结点
31                     TreeNode<K, V> pp = p.parent; // p的父节点
32                     // s和p的结点位置互换
33                     if (s == pr) { // 如果s是p的右子结点,说明s没有左子结点
34                         p.parent = s; // p的父节点指针指向s
35                         s.right = p; // s的右子结点指针指向p, 后面再处理其他指针
36                     } else {
37                         TreeNode<K, V> sp = s.parent; // s的父节点
38                         if ((p.parent = sp) != null) { // p的父节点指针指向s的父节点
39                             if (s == sp.left)
40                                 sp.left = p; // 如果s是其父节点的左子结点,则sp的左子结点指针指向p
41                             else
42                                 sp.right = p; // 如果s是其父节点的右子结点,则sp的右子结点指针指向p
43                         }
44                         if ((s.right = pr) != null) // s的右子结点指针指向p的右子结点
45                             pr.parent = s; // p的右子结点的指针指向s
46                     }
47                     p.left = null; // p的左子树置为空,同原来的s结点
48                     if ((p.right = sr) != null) // 更新其他指针,使得互换完整,p的右子结点指针指向s的右子结点
49                         sr.parent = p;  // s的右子节点的父节点指针指向p
50                     if ((s.left = pl) != null) // s的左子节点指针指向p的左子结点
51                         pl.parent = s; // p的左子结点的父节点指针指向s
52                     if ((s.parent = pp) == null) // 如果s没有父节点,那么s就是根节点
53                         r = s; // root指针指向s
54                     else if (p == pp.left) // 否则,继续更新其他指针,如果p是其原父节点的左子节点,那么p的原父节点的左子结点指针指向s
55                         pp.left = s;
56                     else // 否则,p的原父节点的右子节点指针指向s
57                         pp.right = s;
58                     if (sr != null) // 如果原s结点的右子结点sr不为空,则sr为最后空缺结点位置,平衡红黑树时,便以此位置结点(replacement)为基准,缺失此位置结点之后,再使得红黑树平衡
59                         replacement = sr;
60                     else // 否则,replacement是p结点
61                         replacement = p;
62                 } else if (pl != null) // 如果p的右子节点为空,则replacement是其左子结点
63                     replacement = pl;
64                 else if (pr != null) // 否则,是其右子结点
65                     replacement = pr;
66                 else
67                     replacement = p; // 如果左右子结点均为空,replacement是p结点自己
68                 if (replacement != p) { // 如果replacement不是p结点,在平衡红黑树之前删除p结点,目标结点会转移至replacement结点
69                     TreeNode<K, V> pp = replacement.parent = p.parent; // replacement结点的父节点指针指向p的父节点
70                     if (pp == null)
71                         r = replacement; // 如果replacement结点的父节点为空,则为根节点,root指针指向它
72                     else if (p == pp.left)
73                         pp.left = replacement; // 否则,如果p为其父节点pp的左子结点,令pp的左子结点指针指向replacement
74                     else // 如果p为其父节点pp的右子结点,令pp的右子结点指针指向replacement
75                         pp.right = replacement;
76                     p.left = p.right = p.parent = null; // 置空p的相关指针
77                 }
78 
79                 root = (p.red) ? r : balanceDeletion(r, replacement); // 如果p为红色结点,则直接删除就好,否则,需要平衡红黑树
80 
81                 if (p == replacement) { // 如果replacement就是p结点,解除p的相关指针
82                     TreeNode<K, V> pp;
83                     if ((pp = p.parent) != null) { // p的父节点存在
84                         if (p == pp.left) // 如果p是其父节点的左子结点,令其父节点的左子结点指针置空
85                             pp.left = null;
86                         else if (p == pp.right) // 否则,令其父节点的右子节点指针置空
87                             pp.right = null;
88                         p.parent = null; // 最后令p的父节点指针置空
89                     }
90                 }
91             } finally {
92                 unlockRoot(); // 解除锁
93             }
94             assert checkInvariants(root); // 校验一致性
95             return false; // 不用进行红黑树转链表操作
96         }

读写锁

 1         private final void lockRoot() { // 加锁
 2             if (!U.compareAndSwapInt(this, LOCKSTATE, 0, WRITER)) // 加写锁
 3                 contendedLock(); // 如果CAS失败,以竞争的方式加锁
 4         }
 5 
 6         private final void unlockRoot() { // 解锁
 7             lockState = 0;
 8         }
 9 
10         private final void contendedLock() { // WRITER = 001; WAITER = 010; READER = 100; ~表示取反
11             boolean waiting = false;
12             for (int s;;) {
13                 if (((s = lockState) & ~WAITER) == 0) { // ~WAITER = 101, 表示如果没有线程持有读锁,不会有线程持有写锁,因为与当前线程互斥
14                     if (U.compareAndSwapInt(this, LOCKSTATE, s, WRITER)) { // CAS,设置写状态
15                         if (waiting) // 如果设置过当前线程为等待线程
16                             waiter = null; // 直接清除
17                         return;
18                     }
19                 } else if ((s & WAITER) == 0) { // 如果有线程持有读锁,但没有别的写线程占据waiter
20                     if (U.compareAndSwapInt(this, LOCKSTATE, s, s | WAITER)) { // 尝试设置waiter标志
21                         waiting = true;
22                         waiter = Thread.currentThread(); // 使自己成为等待获取锁的写线程
23                     }
24                 } else if (waiting) // 否则,使自己挂起
25                     LockSupport.park(this);
26             }
27         }

ForwardingNode

 1     static final class ForwardingNode<K, V> extends Node<K, V> {
 2         final Node<K, V>[] nextTable; // 指向新数组
 3 
 4         ForwardingNode(Node<K, V>[] tab) { // 构造方法
 5             super(MOVED, null, null, null);
 6             this.nextTable = tab;
 7         }
 8 
 9         Node<K, V> find(int h, Object k) { // 查找
10             outer: for (Node<K, V>[] tab = nextTable;;) { // 转移至新数组查找
11                 Node<K, V> e;
12                 int n;
13                 if (k == null || tab == null || (n = tab.length) == 0 || (e = tabAt(tab, (n - 1) & h)) == null)
14                     return null; // 没有则返回null
15                 for (;;) {
16                     int eh;
17                     K ek;
18                     if ((eh = e.hash) == h && ((ek = e.key) == k || (ek != null && k.equals(ek)))) // 找到直接返回
19                         return e;
20                     if (eh < 0) {
21                         if (e instanceof ForwardingNode) { // 又遇见转发结点
22                             tab = ((ForwardingNode<K, V>) e).nextTable; // 指向新数组
23                             continue outer; // 类似于递归查找
24                         } else
25                             return e.find(h, k); // 调用结点的查找方法
26                     }
27                     if ((e = e.next) == null) // 没有则返回null
28                         return null;
29                 }
30             }
31         }
32     }

 

ReservationNode

1     static final class ReservationNode<K, V> extends Node<K, V> {
2         ReservationNode() {
3             super(RESERVED, null, null, null);
4         }
5 
6         Node<K, V> find(int h, Object k) {
7             return null;
8         }
9     }

 

通用方法

spread

1     static final int spread(int h) { // 0111 1111 1111 1111 1111 1111 1111 1111
2         return (h ^ (h >>> 16)) & HASH_BITS;
3     }

tableSizeFor

 1     private static final int tableSizeFor(int c) { // 计算table的实际size,返回值(x)是最小的且大小等于c的值,且x & (x - 1) == 0, 即是2的幂次方的值
 2         int n = c - 1; // 定义Y位是从最高位开始第一个为1的位,Y越大,表示位数越高,int中,Y最大是32,即最左边的那个位
 3                        // 如果c已经是2的幂次方的值,那么n的Y位比c的小1,否则,与c的相等,使用n = c - 1,而不是直接使用c,目的是:如果c已经是2的幂次方的值时,直接返回c,而不是c << 1
 4         // n右移1位,再与n作或运算,最后的结果是,Y位为1,(Y-1)位也为1了,
 5         // 比如,n是           0000...1XXX XXXX...XXXX XXXX (X = 0或1),最后的结果是,
 6         n |= n >>> 1; // 0000...11XX XXXX...XXXX XXXX
 7         n |= n >>> 2; // 0000...1111 XXXX...XXXX XXXX
 8         n |= n >>> 4; // 0000...1111 1111...XXXX XXXX
 9         n |= n >>> 8; // 0000...1111 1111...1111 XXXX
10         n |= n >>> 16;// 0000...1111 1111...1111 1111
11         return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; // n + 1 = 0000...10...0
12     }

initTable

 1     private final Node<K, V>[] initTable() {
 2         Node<K, V>[] tab;
 3         int sc;
 4         while ((tab = table) == null || tab.length == 0) { // 由于是并发执行,所以采用死循环内执行CAS操作,保证只有一个线程执行此操作
 5             if ((sc = sizeCtl) < 0) // 说明其他线程正在执行此操作,让出CPU即可
 6                 Thread.yield(); // 自旋一下
 7             else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) { // CAS,成功则执行初始化操作
 8                 try {
 9                     if ((tab = table) == null || tab.length == 0) { // 再次判断,是因为,当前线程初始化时,有一个线程A进入了while里面(因为此时还未给table赋值)
10                                                                     // 但是初始化完成后,sizeCtl又恢复为原来的值,而A线程刚刚走到上面的if分支,由于不满足条件,
11                                                                     // 所以会走else
12                                                                     // if分支,是满足的。所以避免重复初始化,这里需要在判断一次
13                         int n = (sc > 0) ? sc : DEFAULT_CAPACITY; // 计算容量
14                         @SuppressWarnings("unchecked")
15                         Node<K, V>[] nt = (Node<K, V>[]) new Node<?, ?>[n]; // 创建数组
16                         table = tab = nt; // 给table赋值
17                         sc = n - (n >>> 2); // sc = n - n/4 = 3n/4 = 0.75n 实际容量
18                     }
19                 } finally {
20                     sizeCtl = sc; // 最后赋值给sizeCtl
21                 }
22                 break; // 初始化完成,跳出
23             }
24         }
25         return tab; // 返回
26     }

resizeStamp

1     static final int resizeStamp(int n) { // 不同长度数组的戳,唯一
2         return Integer.numberOfLeadingZeros(n) | (1 << (RESIZE_STAMP_BITS - 1));
3     }

 

treeifyBin

 1     private final void treeifyBin(Node<K, V>[] tab, int index) { // 链表转为红黑树
 2         Node<K, V> b;
 3         int n, sc;
 4         if (tab != null) {
 5             if ((n = tab.length) < MIN_TREEIFY_CAPACITY) // 长度没有达到链表转红黑树容量,优先考虑扩容
 6                 tryPresize(n << 1);
 7             else if ((b = tabAt(tab, index)) != null && b.hash >= 0) { // 确认是链表
 8                 synchronized (b) { // 加锁
 9                     if (tabAt(tab, index) == b) { // 再次确认
10                         TreeNode<K, V> hd = null, // 指向头结点
11                                        tl = null; // 指向尾结点
12                         for (Node<K, V> e = b; e != null; e = e.next) { // 遍历链表
13                             TreeNode<K, V> p = new TreeNode<K, V>(e.hash, e.key, e.val, null, null); // 构建红黑树结点
14                             if ((p.prev = tl) == null)
15                                 hd = p;
16                             else
17                                 tl.next = p; // tl向后移动,以拼接结点
18                             tl = p;
19                         }
20                         setTabAt(tab, index, new TreeBin<K, V>(hd)); // 设置hash桶,指向红黑树包装结点,在包装结点(TreeBin)内部构建红黑树
21                     }
22                 }
23             }
24         }
25     }

 

untreeify

 1     static <K, V> Node<K, V> untreeify(Node<K, V> b) {
 2         Node<K, V> hd = null, tl = null;
 3         for (Node<K, V> q = b; q != null; q = q.next) { // 以链表方式遍历
 4             Node<K, V> p = new Node<K, V>(q.hash, q.key, q.val, null); // 构建链表结点
 5             if (tl == null)
 6                 hd = p; // 头结点
 7             else
 8                 tl.next = p; // 尾结点
 9             tl = p; // 更新尾结点
10         }
11         return hd;
12     }

 

基本操作

put

 1     final V putVal(K key, V value, boolean onlyIfAbsent) {
 2         if (key == null || value == null) // 参数校验
 3             throw new NullPointerException();
 4         int hash = spread(key.hashCode()); // 根据key的hashCode计算hash值
 5         int binCount = 0; // hash桶存储的链表时,表示元素个数;若是红黑树,固定为2,既能保证进行扩容检查,又不触发链表转红黑树树操作
 6         for (Node<K, V>[] tab = table;;) {
 7             Node<K, V> f;
 8             int n, i, fh;
 9             if (tab == null || (n = tab.length) == 0)
10                 tab = initTable(); // 初始化table
11             else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) { // (n - 1) & hash, 计算table下标
12                 if (casTabAt(tab, i, null, new Node<K, V>(hash, key, value, null))) // 数组索引i位置为空,则CAS该元素到此位置
13                     break; // 成功则退出for循环
14             } else if ((fh = f.hash) == MOVED) // 如果是转发结点(ForwardingNode),说明此刻正在扩容
15                 tab = helpTransfer(tab, f); // 帮助扩容
16             else {
17                 V oldVal = null;
18                 synchronized (f) { // 对桶的首结点加锁
19                     if (tabAt(tab, i) == f) { // 万一扩容后,该索引位置已经替换为转发结点了,则重新开始循环
20                         if (fh >= 0) { // 链表
21                             binCount = 1; // 已存在首结点,这里为1
22                             for (Node<K, V> e = f;; ++binCount) {
23                                 K ek;
24                                 if (e.hash == hash && ((ek = e.key) == key || (ek != null && key.equals(ek)))) { // 该结点“存在”
25                                     oldVal = e.val; // 取得老的val值
26                                     if (!onlyIfAbsent) // 根据条件
27                                         e.val = value; // 设置新的值
28                                     break;
29                                 }
30                                 Node<K, V> pred = e; // 备注前一个结点
31                                 if ((e = e.next) == null) { // 往后遍历,直到最后一个结点
32                                     pred.next = new Node<K, V>(hash, key, value, null); // 创建新的结点,并使得最后一个结点指向自己,使自己成为新的最后一个结点
33                                     break;
34                                 }
35                             }
36                         } else if (f instanceof TreeBin) { // 红黑树
37                             Node<K, V> p;
38                             binCount = 2; // 固定为2,既能保证进行扩容检查,又不触发链表转红黑树树操作
39                             if ((p = ((TreeBin<K, V>) f).putTreeVal(hash, key, value)) != null) { // 调用红黑树的put方法
40                                 oldVal = p.val; // 取得老的val值
41                                 if (!onlyIfAbsent) // 根据条件
42                                     p.val = value; // 设置新的值
43                             }
44                         }
45                     }
46                 }
47                 if (binCount != 0) {
48                     if (binCount >= TREEIFY_THRESHOLD) // 达到阈值,则触发链表转红黑树操作
49                         treeifyBin(tab, i); // 链表转红黑树
50                     if (oldVal != null)
51                         return oldVal; // 替换操作,无需更改计数值
52                     break;
53                 }
54             }
55         }
56         addCount(1L, binCount); // 计数加1
57         return null;
58     }

get

 1     public V get(Object key) {
 2         Node<K, V>[] tab;
 3         Node<K, V> e, p;
 4         int n, eh;
 5         K ek;
 6         int h = spread(key.hashCode()); // 计算hash值
 7         if ((tab = table) != null && (n = tab.length) > 0 && (e = tabAt(tab, (n - 1) & h)) != null) { // 定位hash桶
 8             if ((eh = e.hash) == h) { // 如果hash值相等
 9                 if ((ek = e.key) == key || (ek != null && key.equals(ek))) // 并且key相等,直接返回
10                     return e.val;
11             } else if (eh < 0) // 如果hash值小于0,说明为特殊结点
12                 return (p = e.find(h, key)) != null ? p.val : null; // 调用结点的查找方法
13             while ((e = e.next) != null) { // 链表方式查找
14                 if (e.hash == h && ((ek = e.key) == key || (ek != null && key.equals(ek)))) // hash相等,key相等,返回,否则,循环继续
15                     return e.val;
16             }
17         }
18         return null;
19     }

remove

remove

1     public V remove(Object key) {
2         return replaceNode(key, null, null); // 删除,用null替换原来的值
3     }

replaceNode

 1     final V replaceNode(Object key, V value, Object cv) {
 2         int hash = spread(key.hashCode()); // 计算hash值
 3         for (Node<K, V>[] tab = table;;) {
 4             Node<K, V> f;
 5             int n, i, fh;
 6             if (tab == null || (n = tab.length) == 0 || (f = tabAt(tab, i = (n - 1) & hash)) == null) // 找不到目标结点,直接跳出循环
 7                 break;
 8             else if ((fh = f.hash) == MOVED) // 发现是转发结点,说明此时正在扩容
 9                 tab = helpTransfer(tab, f); // 去帮助扩容
10             else {
11                 V oldVal = null;
12                 boolean validated = false; // 操作是否有效
13                 synchronized (f) { // 对hash桶第一个结点加锁
14                     if (tabAt(tab, i) == f) { // 再次判定f是否是hash桶i的第一个结点
15                         if (fh >= 0) { // 链表结点
16                             validated = true; // 有效
17                             for (Node<K, V> e = f, pred = null;;) {
18                                 K ek;
19                                 if (e.hash == hash && ((ek = e.key) == key || (ek != null && key.equals(ek)))) { // 找到目标结点
20                                     V ev = e.val;
21                                     if (cv == null || cv == ev || (ev != null && cv.equals(ev))) { // 判断value值是否被修改过,如果修改过(已经释放了锁,所以此线程能再获取到锁,其实是不同对象的),则退出
22                                         oldVal = ev; // 没有被修改过,记录老的value值
23                                         if (value != null)
24                                             e.val = value; // 替换成新值
25                                         else if (pred != null) // 如果新值为空,则删除此结点
26                                             pred.next = e.next; // 此结点的前驱结点和后继结点直接相连
27                                         else
28                                             setTabAt(tab, i, e.next); // 如果此结点没有前驱结点,说明它是hash桶的第一个结点,此时则设置其后继结点为hash桶第一个结点
29                                     }
30                                     break;
31                                 }
32                                 pred = e; // 记录上一个节点
33                                 if ((e = e.next) == null) // 右移遍历链表
34                                     break;
35                             }
36                         } else if (f instanceof TreeBin) { // 如果是红黑树结点
37                             validated = true; // 有效
38                             TreeBin<K, V> t = (TreeBin<K, V>) f; // 红黑树包装结点
39                             TreeNode<K, V> r, p;
40                             if ((r = t.root) != null && (p = r.findTreeNode(hash, key, null)) != null) { // 查找目标结点
41                                 V pv = p.val;
42                                 if (cv == null || cv == pv || (pv != null && cv.equals(pv))) { // 判断value值是否被修改过,如果修改过(可能已经释放了锁,所以此线程可以再获取到锁,其实是不同对象的),则退出
43                                     oldVal = pv; // 没有被修改过,记录老的value值
44                                     if (value != null)
45                                         p.val = value; // 替换成新值
46                                     else if (t.removeTreeNode(p)) // 如果新值为空,则删除此结点
47                                         setTabAt(tab, i, untreeify(t.first)); // 如果需要转换为链表,则执行红黑树转链表操作
48                                 }
49                             }
50                         }
51                     }
52                 }
53                 if (validated) { // 如果操作有效
54                     if (oldVal != null) {
55                         if (value == null) // 并且是删除操作
56                             addCount(-1L, -1); // 计数减一
57                         return oldVal;
58                     }
59                     break;
60                 }
61             }
62         }
63         return null;
64     }

扩容

addCount

 1     private final void addCount(long x, int check) { // x:要更改的数目;check:判断是否扩容,小于0,无需扩容;小于等于1且有竞争计数线程,无需扩容;其余情况会考虑扩容  
 2         CounterCell[] as;
 3         long b, s;
 4         if ((as = counterCells) != null || !U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) { // 首次计数(counterCells==null)且CAS成功,跳过if分支
 5             CounterCell a;
 6             long v;
 7             int m;
 8             boolean uncontended = true;
 9             if (as == null || (m = as.length - 1) < 0 || (a = as[ThreadLocalRandom.getProbe() & m]) == null
10                     || !(uncontended = U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))) { // 如果counterCells还没被初始化,或者当前线程hash的Cell还为被使用,或者CAS失败,走fullAddCount
11                 fullAddCount(x, uncontended); // 优先将计数算在baseCount上,如果有竞争,便采用分槽计数,详见fullAddCount方法
12                 return;
13             }
14             if (check <= 1) // 小于等于1且有竞争计数线程,无需扩容
15                 return;
16             s = sumCount(); // 计算总数目
17         }
18         if (check >= 0) { // 检查扩容
19             Node<K, V>[] tab, nt;
20             int n, sc;
21             // 大于扩容阈值,table不为空,且长度小于最大值
22             while (s >= (long) (sc = sizeCtl) && (tab = table) != null && (n = tab.length) < MAXIMUM_CAPACITY) {
23                 int rs = resizeStamp(n); // 计算当前数组的长度戳,防止重叠扩容
24                 if (sc < 0) { // I
25                     if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 || sc == rs + MAX_RESIZERS
26                             || (nt = nextTable) == null || transferIndex <= 0) //II 如果不满足扩容条件,跳出循环
27                         break;
28                     if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) //III 扩容线程加1
29                         transfer(tab, nt); // 执行转移任务
30                 } else if (U.compareAndSwapInt(this, SIZECTL, sc, (rs << RESIZE_STAMP_SHIFT) + 2)) // 第一个执行转移任务的线程
31                     transfer(tab, null);
32                 s = sumCount(); // 计算总数
33             }
34         }
35     }

helpTransfer

 1     final Node<K, V>[] helpTransfer(Node<K, V>[] tab, Node<K, V> f) { // 帮助扩容
 2         Node<K, V>[] nextTab;
 3         int sc;
 4         if (tab != null && (f instanceof ForwardingNode) && (nextTab = ((ForwardingNode<K, V>) f).nextTable) != null) { // 根据f找到nextTable
 5             int rs = resizeStamp(tab.length); // 计算当前扩容数组长度戳
 6             while (nextTab == nextTable && table == tab && (sc = sizeCtl) < 0) {
 7                 if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 || sc == rs + MAX_RESIZERS || transferIndex <= 0) // 如果不满足扩容条件,跳出循环
 8                     break;
 9                 if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) { // 扩容线程加1
10                     transfer(tab, nextTab); // 执行转移任务
11                     break;
12                 }
13             }
14             return nextTab;
15         }
16         return table;
17     }

tryPresize

 1     private final void tryPresize(int size) {
 2         int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY : tableSizeFor(size + (size >>> 1) + 1); // 预计算下一次table容量
 3         int sc;
 4         while ((sc = sizeCtl) >= 0) {
 5             Node<K, V>[] tab = table;
 6             int n;
 7             if (tab == null || (n = tab.length) == 0) { // 初始化table
 8                 n = (sc > c) ? sc : c;
 9                 if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) { // CAS
10                     try {
11                         if (table == tab) {
12                             @SuppressWarnings("unchecked")
13                             Node<K, V>[] nt = (Node<K, V>[]) new Node<?, ?>[n]; // 新建table数组
14                             table = nt;
15                             sc = n - (n >>> 2); // 下一次table容量
16                         }
17                     } finally {
18                         sizeCtl = sc;
19                     }
20                 }
21             } else if (c <= sc || n >= MAXIMUM_CAPACITY) // 已经扩容过了或超出最大容量
22                 break;
23             else if (tab == table) {
24                 int rs = resizeStamp(n);  // 计算当前扩容数组长度戳
25                 if (sc < 0) {
26                     Node<K, V>[] nt;
27                     if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 || sc == rs + MAX_RESIZERS
28                             || (nt = nextTable) == null || transferIndex <= 0) // 如果不满足扩容条件,跳出循环
29                         break;
30                     if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) // 扩容线程加1
31                         transfer(tab, nt); // 执行转移任务
32                 } else if (U.compareAndSwapInt(this, SIZECTL, sc, (rs << RESIZE_STAMP_SHIFT) + 2)) // 第一个执行转移任务的线程
33                     transfer(tab, null);
34             }
35         }
36     }

transfer

  1     private final void transfer(Node<K, V>[] tab, Node<K, V>[] nextTab) {
  2         int n = tab.length, stride; // n:数组长度,stride:步长,每个线程处理一段数据
  3         if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE) // 根据CPU的个数选择合适的步长,一个核心按8个线程算,线程越多,步长越小
  4             stride = MIN_TRANSFER_STRIDE; // 最小步长
  5         if (nextTab == null) { // 初始化
  6             try {
  7                 @SuppressWarnings("unchecked")
  8                 Node<K, V>[] nt = (Node<K, V>[]) new Node<?, ?>[n << 1]; // 新数组长度是原来的两倍,扩容
  9                 nextTab = nt; // 赋值给nextTab
 10             } catch (Throwable ex) { // 内存溢出情况
 11                 sizeCtl = Integer.MAX_VALUE;
 12                 return;
 13             }
 14             nextTable = nextTab; // nextTable变量指向新数组
 15             transferIndex = n; // 转移索引,旧数组,从右往左,每次移动步长的距离,n -> 0
 16         }
 17         int nextn = nextTab.length; // 新数组的长度
 18         ForwardingNode<K, V> fwd = new ForwardingNode<K, V>(nextTab); // 转发结点,旧数组里,每个hash桶处理完成后,替换成该结点,写操作遇见此结点就知道该桶已经转移完成,继续检查别的桶,读操作遇见它,就会根据此结点保存的信息,转移到新数组查询
 19         boolean advance = true; // 表明任务是否向前推进,是,则定为下一个要处理的桶,否,则继续处理当前桶
 20         boolean finishing = false; // 表明整个扩容任务是否完成,最后一个线程会处理一些收尾工作:重新扫一遍数组,完成遗漏的任务;更新属性的值
 21         for (int i = 0, bound = 0;;) {
 22             Node<K, V> f;
 23             int fh;
 24             while (advance) { // 任务向前推进
 25                 int nextIndex, nextBound;
 26                 if (--i >= bound || finishing) // i ∈ [bound, lastBound),如果i越界,或已经结束,不再推进
 27                     advance = false;
 28                 else if ((nextIndex = transferIndex) <= 0) { // transferIndex ∈ [0, length), 如果转移索引越界,不再推进
 29                     i = -1;
 30                     advance = false;
 31                 } else if (U.compareAndSwapInt(this, TRANSFERINDEX, nextIndex,
 32                         nextBound = (nextIndex > stride ? nextIndex - stride : 0))) { // CAS更新transferIndex减去stride步长
 33                     bound = nextBound; // 当前低边界
 34                     i = nextIndex - 1; // 当前高边界,从高(右)向低(左)移动
 35                     advance = false; // 先不推进索引,开始做任务
 36                 }
 37             }
 38             if (i < 0 || i >= n || i + n >= nextn) { // 边界检查,i ∈ [0, n), i + n要小于nextn,因为原数组i索引处的数据会被复制到新数组索引i和i + n处
 39                 int sc;
 40                 if (finishing) { // 如果任务将要结束,说明当前线程是最后一个扩容线程
 41                     nextTable = null; // 置空
 42                     table = nextTab; // 指向新数组
 43                     sizeCtl = (n << 1) - (n >>> 1); // 2n - n/2 = 2 * 3n/4
 44                     return;
 45                 }
 46                 if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, sc - 1)) { // 扩容线程个数减1,表明当前线程将要退出
 47                     if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT) // 如果当前线程不是最后一个扩容线程
 48                         return; // 直接退出
 49                     finishing = advance = true; // 否则,最后一个线程执行收尾工作
 50                     i = n; // 从头再检查一遍
 51                 }
 52             } else if ((f = tabAt(tab, i)) == null) // 如果该hash桶为空,则放入转移结点
 53                 advance = casTabAt(tab, i, null, fwd);
 54             else if ((fh = f.hash) == MOVED) // 如果该hash桶里是转移结点,直接跳过
 55                 advance = true; // 任务向前推进
 56             else {
 57                 synchronized (f) { // 对该hash桶上的首元素进行加锁,f不一定是桶的首元素,加锁期间,有可能有put操作,新结点是在头部插入的,所以加锁后需要再检查一遍
 58                     if (tabAt(tab, i) == f) { // 再次检查,f是否是i桶的首元素
 59                         Node<K, V> ln, hn;
 60                         if (fh >= 0) { // 链表
 61                             int runBit = fh & n; // 二进制第n位的01情况,以此分为两部分,分别复制到新数组的i桶和i + n桶处
 62                             Node<K, V> lastRun = f; // 执行链表中的某个结点,从这个结点开始,后面的所有结点的runBit相同,...->0->1->0->...>1->0->1(lastRun)->1->1, 或者...->0->1->0->...>1->1->0(lastRun)->0->0
 63                             for (Node<K, V> p = f.next; p != null; p = p.next) {
 64                                 int b = p.hash & n; // 计算当前结点的"runBit"
 65                                 if (b != runBit) { // 如果变了
 66                                     runBit = b; // 更新runBit为当前结点的"runBit"
 67                                     lastRun = p; // 指向当前结点
 68                                 }
 69                             }
 70                             if (runBit == 0) { // 等于0的给ln
 71                                 ln = lastRun; // lastRun及其之后的结点,不必复制,直接重用到新数组里
 72                                 hn = null;
 73                             } else { // 等于1的给hn
 74                                 hn = lastRun;
 75                                 ln = null;
 76                             }
 77                             for (Node<K, V> p = f; p != lastRun; p = p.next) { // 遍历链表,根据runBit分成两部分
 78                                 int ph = p.hash;
 79                                 K pk = p.key;
 80                                 V pv = p.val;
 81                                 if ((ph & n) == 0)
 82                                     ln = new Node<K, V>(ph, pk, pv, ln); // 从头部插入结点
 83                                 else
 84                                     hn = new Node<K, V>(ph, pk, pv, hn); // 从头部插入结点
 85                             }
 86                             setTabAt(nextTab, i, ln); // 新数组i桶
 87                             setTabAt(nextTab, i + n, hn); // 新数组i + n桶
 88                             setTabAt(tab, i, fwd); // 原数组i桶替换成转移结点
 89                             advance = true; // 当前桶任务完成,可以向前推进了
 90                         } else if (f instanceof TreeBin) { // 红黑树
 91                             TreeBin<K, V> t = (TreeBin<K, V>) f;
 92                             TreeNode<K, V> lo = null, // 指向runBit等于0的头结点
 93                                        loTail = null; // 指向runBit等于0的尾结点
 94                             TreeNode<K, V> hi = null, // 指向runBit等于1的头结点
 95                                        hiTail = null; // 指向runBit等于1的尾结点
 96                             int lc = 0, // 记录链表长度,据此决定是否要将红黑树转成链表
 97                                 hc = 0; // 记录链表长度
 98                             for (Node<K, V> e = t.first; e != null; e = e.next) { // 以链表的方式遍历结点
 99                                 int h = e.hash; // 当前结点的hash值
100                                 TreeNode<K, V> p = new TreeNode<K, V>(h, e.key, e.val, null, null); // 创建新结点,e的复制
101                                 if ((h & n) == 0) {
102                                     if ((p.prev = loTail) == null)
103                                         lo = p; // 头节点
104                                     else
105                                         loTail.next = p; // 尾节点的next属性指向新结点
106                                     loTail = p; // 更新尾结点
107                                     ++lc; // 计数加1
108                                 } else { // 同上
109                                     if ((p.prev = hiTail) == null)
110                                         hi = p;
111                                     else
112                                         hiTail.next = p;
113                                     hiTail = p;
114                                     ++hc;
115                                 }
116                             }
117                             ln = (lc <= UNTREEIFY_THRESHOLD) ? untreeify(lo) : (hc != 0) ? new TreeBin<K, V>(lo) : t; // 根据lc判断是否转成链表,如果hc为0,表明自己承接整个红黑树,直接指向t就可以了,也省了构造TreeBin的过程
118                             hn = (hc <= UNTREEIFY_THRESHOLD) ? untreeify(hi) : (lc != 0) ? new TreeBin<K, V>(hi) : t; // 同上
119                             setTabAt(nextTab, i, ln); // 新数组i桶
120                             setTabAt(nextTab, i + n, hn); // 新数组i + n桶
121                             setTabAt(tab, i, fwd); // 原数组i桶替换成转移结点
122                             advance = true; // 当前桶任务完成,可以向前推进了
123                         }
124                     }
125                 }
126             }
127         }
128     }

扩容重叠

如果不考虑stamp的差异
不同长度的数组对应不同的stamp,具体见resizeStamp方法
长度为n的数组扩容为2n,假设stamp_1表示为[n->2n]
长度为2n的数组扩容为4n,假设stamp_1表示为[2n->4n]
对于stamp_1版本的扩容,有A和B线程执行扩容,线程A执行过程中(I处,tab的长度为n)让出了CPU时间片,最后由线程B完成了扩容
由于stamp_1版本扩容已经完成,可进行stamp_2版本的扩容,且由C线程执行扩容,在此期间,线程A得到了时间片继续执行(II处,nt的长度为4n)
并继续执行至III处(下一步便是进入transfer方法),而线程C完成了扩容任务后,发现自己不是最后一个扩容线程(线程A才是,n->4n),直接就退出了,收尾工作交给A
线程来做,而A线程是基于长度为n的数组做的任务,对于stamp_2版本的2n->4n扩容任务可能会有遗漏,这边是扩容重叠导致的问题,也是resizeStamp存在的必要性

遍历器

TableStack

1     static final class TableStack<K, V> {
2         int length; // 长度
3         int index; // 索引
4         Node<K, V>[] tab; // 数组
5         TableStack<K, V> next; // 指向下一个
6     }

Traverser

类的定义
    static class Traverser<K, V> {}
属性
1         Node<K, V>[] tab; // 当前数组,扩容时更新
2         Node<K, V> next; // 新数组,扩容完成后的数组
3         TableStack<K, V> stack, spare; // 保存/恢复转发结点
4         int index; // 下一个要读取hash桶的索引
5         int baseIndex; // 起始索引
6         int baseLimit; // 终止索引
7         final int baseSize; // 数组起始长度
构造方法
1         Traverser(Node<K, V>[] tab, int size, int index, int limit) { // 构造方法
2             this.tab = tab;
3             this.baseSize = size;
4             this.baseIndex = this.index = index;
5             this.baseLimit = limit;
6             this.next = null;
7         }
advance
 1         final Node<K, V> advance() { // 遍历器指针往前移动下一个有效结点,并返回此结点,如果没有就返回null
 2             Node<K, V> e;
 3             if ((e = next) != null) // 如果e的下一个结点不为空,则指向此结点,即为有效结点,稍后返回
 4                 e = e.next;
 5             for (;;) {
 6                 Node<K, V>[] t;
 7                 int i, n;
 8                 if (e != null) // e存在,直接返回
 9                     return next = e; // 更新next指针
10                 if (baseIndex >= baseLimit || (t = tab) == null || (n = t.length) <= (i = index) || i < 0) // 边界检查
11                     return next = null; // 结点不存在,直接返回null
12                 if ((e = tabAt(t, i)) != null && e.hash < 0) { // 特殊结点
13                     if (e instanceof ForwardingNode) { // 如果是转发结点
14                         tab = ((ForwardingNode<K, V>) e).nextTable; // 指向新数组,遍历迁移至此
15                         e = null; // 不可直接返回转发结点,置为空
16                         pushState(t, i, n); // 入栈
17                         continue; // 继续,遍历新桶
18                     } else if (e instanceof TreeBin)
19                         e = ((TreeBin<K, V>) e).first; // 如果是红黑树,指向头结点
20                     else // 保留结点
21                         e = null; // 置空
22                 }
23                 if (stack != null) // 出栈,或更新索引至i+len, 因为原数组i索引处的元素会复制到新数组i索引处和i+len索引处(len为原数组长度)
24                     recoverState(n);
25                 else if ((index = i + baseSize) >= n) // 更新元素索引(i++或i+len)
26                     index = ++baseIndex;
27             }
28         }
pushState
 1         private void pushState(Node<K, V>[] t, int i, int n) {
 2             TableStack<K, V> s = spare; // 重用
 3             if (s != null) // 不为空,其next指向spare
 4                 spare = s.next;
 5             else // 否则新建一个
 6                 s = new TableStack<K, V>();
 7             s.tab = t; // 数组信息
 8             s.length = n; // 长度信息
 9             s.index = i; // 索引信息
10             s.next = stack; // 指向栈顶
11             stack = s; // 更新栈顶
12         }
recoverState
 1         private void recoverState(int n) {
 2             TableStack<K, V> s;
 3             int len;
 4             while ((s = stack) != null && (index += (len = s.length)) >= n) { // 出栈
 5                 n = len;
 6                 index = s.index; // 索引信息
 7                 tab = s.tab; // 数组信息
 8                 s.tab = null; // 置空
 9                 TableStack<K, V> next = s.next; // 弹出
10                 s.next = spare; // 重用
11                 stack = next; // 更新栈顶
12                 spare = s; // 执行弹出的栈元素
13             }
14             if (s == null && (index += baseSize) >= n) // 栈为空,索引处于新数组后半部分,则更新索引,原数组右移
15                 index = ++baseIndex;
16         }

红黑树

性质

(1) 每个结点要么为红色要么为黑色。

(2) 根结点为黑色。

(3) 每个叶结点(NIL)是黑色的。

(4) 如果节点为红色,其子节点必须为黑色。

(5) 从一个节点到节点的后代节点的所有路径都包含相同数量的黑节点。

添加

Case 1

X的叔叔结点(U)是红色结点

Case 2

X的叔叔节点(U)是黑色的,X是(P的)右子结点

Case 3

X的叔叔节点(U)是黑色的,X是(P的)左子结点

case1可以递归转化为case2或3。

case2可以转化为case3。

case3可以结束。

删除

Case 1

X的兄弟节点(B)是红色结点

Case 2

X的兄弟节点(B)为黑色结点,B的两个子节点(N)为黑色结点

Case 3

X的兄弟节点(B)为黑色,B的左子结点为红色,右子结点为黑色结点

Case 4

X的兄弟节点(B)为黑色,B的右子节点为红色。

 

case1可以转化为案例2或3或4。

case2递归转化为案例3或4。

case3可以转化为案例4。

case4可以结束。

rotateLeft

 1         static <K, V> TreeNode<K, V> rotateLeft(TreeNode<K, V> root, TreeNode<K, V> p) {
 2             TreeNode<K, V> r, pp, rl;
 3             if (p != null && (r = p.right) != null) { // 结点p及其右子结点r不为空
 4                 if ((rl = p.right = r.left) != null) // 结点r的左子结点不为空,并赋值给p的right指针,使其成为p的右子结点
 5                     rl.parent = p; // 更新rl的父节点为p
 6                 if ((pp = r.parent = p.parent) == null) // 使r的parent指针指向p的父节点,若为空,说明r已经是根节点,并赋值给root变量
 7                     (root = r).red = false;
 8                 else if (pp.left == p) // 否则,p的父节点pp存在,如果p是pp的左子结点,则更新pp的左子结点为r
 9                     pp.left = r;
10                 else // 否则,更新pp的右子结点为r
11                     pp.right = r;
12                 r.left = p; // p成为r的左子结点
13                 p.parent = r; // r成为p的父节点
14             }
15             return root; // 返回
16         }

rotateRight

 1         static <K, V> TreeNode<K, V> rotateRight(TreeNode<K, V> root, TreeNode<K, V> p) { // 对称
 2             TreeNode<K, V> l, pp, lr;
 3             if (p != null && (l = p.left) != null) {
 4                 if ((lr = p.left = l.right) != null)
 5                     lr.parent = p;
 6                 if ((pp = l.parent = p.parent) == null)
 7                     (root = l).red = false;
 8                 else if (pp.right == p)
 9                     pp.right = l;
10                 else
11                     pp.left = l;
12                 l.right = p;
13                 p.parent = l;
14             }
15             return root;
16         }

balanceInsertion

 1         static <K, V> TreeNode<K, V> balanceInsertion(TreeNode<K, V> root, TreeNode<K, V> x) { // 每插入一个结点,便执行此方法,以维持红黑树性质
 2             x.red = true; // 新插入的结点一定是红色结点
 3             for (TreeNode<K, V> xp, xpp, xppl, xppr;;) {
 4                 if ((xp = x.parent) == null) { // 如果x的父结点不存在,说明x是根结点
 5                     x.red = false; // 根节点颜色设为黑色,红黑树性质
 6                     return x;
 7                 } else if (!xp.red || (xpp = xp.parent) == null) // 如果x的父节点是黑色结点,则直接插入,符合红黑树性质;或者x的父节点xp是红色结点,但是xp的父结点为空,说明xp是根节点,那么也直接插入,因为别的线程稍后会把根节点xp置为黑色结点
 8                     return root;
 9                 if (xp == (xppl = xpp.left)) { // 如果x的父节点xp是xp的父结点的左子结点
10                     if ((xppr = xpp.right) != null && xppr.red) { // case1,
11                                                                     // 如果x的叔叔结点xppr存在,且是红色结点
12                         xppr.red = false; // 叔叔结点设置为黑色结点
13                         xp.red = false; // 父亲结点设置为黑色结点
14                         xpp.red = true; // 爷爷结点设置为红色结点
15                         x = xpp; // 待平衡结点转移至爷爷结点,一直循环,直到根节点,或中途满足红黑树性质退出
16                     } else {
17                         if (x == xp.right) { // case2, x结点是其父节点的右子结点
18                             root = rotateLeft(root, x = xp); // 左旋,且x指向了x的父节点
19                             xpp = (xp = x.parent) == null ? null : xp.parent; // 更新xp和xpp,分别指向x的父节点和爷爷结点
20                         }
21                         if (xp != null) { // case3, x的父节点存在,且x的叔叔结点为黑色结点
22                             xp.red = false; // x的父节点置为黑色结点
23                             if (xpp != null) { // 如果爷爷结点也存在
24                                 xpp.red = true; // 置为红色结点
25                                 root = rotateRight(root, xpp); // 右旋
26                             }
27                         }
28                     }
29                 } else {
30                     if (xppl != null && xppl.red) { // x为右子结点,对称
31                         xppl.red = false;
32                         xp.red = false;
33                         xpp.red = true;
34                         x = xpp;
35                     } else {
36                         if (x == xp.left) {
37                             root = rotateRight(root, x = xp);
38                             xpp = (xp = x.parent) == null ? null : xp.parent;
39                         }
40                         if (xp != null) {
41                             xp.red = false;
42                             if (xpp != null) {
43                                 xpp.red = true;
44                                 root = rotateLeft(root, xpp);
45                             }
46                         }
47                     }
48                 }
49             }
50         }

balanceDeletion

 1         static <K, V> TreeNode<K, V> balanceDeletion(TreeNode<K, V> root, TreeNode<K, V> x) {
 2             for (TreeNode<K, V> xp, xpl, xpr;;) {
 3                 if (x == null || x == root) // x为空,或为根节点,直接返回
 4                     return root;
 5                 else if ((xp = x.parent) == null) { // x的父节点xp为空,说明x就是根节点
 6                     x.red = false; // 置为黑色结点
 7                     return x; // 返回
 8                 } else if (x.red) { // 如果x是红色结点,直接置为黑色,并返回
 9                     x.red = false;
10                     return root;
11                 } else if ((xpl = xp.left) == x) { // 如果x是xp的左子结点
12                     if ((xpr = xp.right) != null && xpr.red) { // case1, 兄弟结点xpr不为空,且为红色
13                         xpr.red = false; // 兄弟结点置为黑色结点
14                         xp.red = true; // 父节点置为红色结点
15                         root = rotateLeft(root, xp); // 左旋
16                         xpr = (xp = x.parent) == null ? null : xp.right; // 更新xp和xpr, 分别为x的父节点和兄弟结点
17                     }
18                     if (xpr == null) // 如果兄弟结点为空,目标结点x转移至其父节点xp
19                         x = xp;
20                     else {
21                         TreeNode<K, V> sl = xpr.left, sr = xpr.right;
22                         if ((sr == null || !sr.red) && (sl == null || !sl.red)) { // case2, 两个侄子结点不存在,或为黑色结点
23                             xpr.red = true; // 兄弟结点设置为红色结点,目标结点转移至其父节点
24                             x = xp;
25                         } else {
26                             if (sr == null || !sr.red) { // case3, 右侄子结点不存在,或为黑色结点
27                                 if (sl != null) // 左侄子结点若存在,那么一定是红色结点
28                                     sl.red = false; // 置为黑色结点
29                                 xpr.red = true; // 兄弟结点置红色结点
30                                 root = rotateRight(root, xpr); // 右旋
31                                 xpr = (xp = x.parent) == null ? null : xp.right; // 更新xp和xpr,使得分别成为x的父节点和兄弟结点
32                             }
33                             if (xpr != null) { // case4, 兄弟结点不为空
34                                 xpr.red = (xp == null) ? false : xp.red; // 若父节点为空,则其兄弟结点置黑色,否则置为红色
35                                 if ((sr = xpr.right) != null) // 右侄子结点不为空
36                                     sr.red = false; // 置黑色结点
37                             }
38                             if (xp != null) { // 父节点xp不为空
39                                 xp.red = false; // 置为黑色结点
40                                 root = rotateLeft(root, xp); // 左旋
41                             }
42                             x = root;
43                         }
44                     }
45                 } else { // 对称
46                     if (xpl != null && xpl.red) {
47                         xpl.red = false;
48                         xp.red = true;
49                         root = rotateRight(root, xp);
50                         xpl = (xp = x.parent) == null ? null : xp.left;
51                     }
52                     if (xpl == null)
53                         x = xp;
54                     else {
55                         TreeNode<K, V> sl = xpl.left, sr = xpl.right;
56                         if ((sl == null || !sl.red) && (sr == null || !sr.red)) {
57                             xpl.red = true;
58                             x = xp;
59                         } else {
60                             if (sl == null || !sl.red) {
61                                 if (sr != null)
62                                     sr.red = false;
63                                 xpl.red = true;
64                                 root = rotateLeft(root, xpl);
65                                 xpl = (xp = x.parent) == null ? null : xp.left;
66                             }
67                             if (xpl != null) {
68                                 xpl.red = (xp == null) ? false : xp.red;
69                                 if ((sl = xpl.left) != null)
70                                     sl.red = false;
71                             }
72                             if (xp != null) {
73                                 xp.red = false;
74                                 root = rotateRight(root, xp);
75                             }
76                             x = root;
77                         }
78                     }
79                 }
80             }
81         }

checkInvariants

 1         static <K, V> boolean checkInvariants(TreeNode<K, V> t) { // 检查一致性
 2             TreeNode<K, V> tp = t.parent, tl = t.left, tr = t.right, tb = t.prev, tn = (TreeNode<K, V>) t.next;
 3             if (tb != null && tb.next != t) // 若前驱结点tb不为空,则tb的后继结点应为当前结点t
 4                 return false;
 5             if (tn != null && tn.prev != t) // 若继结点tn不为空,则tn的前驱结点应为当前结点t
 6                 return false;
 7             if (tp != null && t != tp.left && t != tp.right) // 若父节点tp不为空,则当前结点t要么是tp的左子结点,要么是tp的右子结点
 8                 return false;
 9             if (tl != null && (tl.parent != t || tl.hash > t.hash)) // 若左子结点tl不为空,那么tl的父节点是当前结点,且hash值小于等于当前结点的hash值
10                 return false;
11             if (tr != null && (tr.parent != t || tr.hash < t.hash)) // 若右子结点tr不为空,那么tr的父节点是当前结点,且hash值大于等于当前结点的hash值
12                 return false;
13             if (t.red && tl != null && tl.red && tr != null && tr.red) // 如果当前结点是红色结点,则它的两个子结点都不能为红色,红黑树的性质:如果一个节点是红色的,则它的子节点必须是黑色的,条件应为:t.red && ((tl != null && tl.red) || (tr != null && tr.red))
14                 return false;
15             if (tl != null && !checkInvariants(tl)) // 如果左子结点不为空,则检查左子树
16                 return false;
17             if (tr != null && !checkInvariants(tr)) // 如果右子结点不为空,则检查右子树
18                 return false;
19             return true;
20         }

分槽计数

fullAddCount

 1     private final void fullAddCount(long x, boolean wasUncontended) {
 2         int h;
 3         if ((h = ThreadLocalRandom.getProbe()) == 0) { // 给当前线程生成一个非0的hash值
 4             ThreadLocalRandom.localInit(); // force initialization
 5             h = ThreadLocalRandom.getProbe();
 6             wasUncontended = true;
 7         }
 8         boolean collide = false; // hash取模得到的hash桶不为空,此值设为true,有扩容意向
 9         for (;;) {
10             CounterCell[] as;
11             CounterCell a;
12             int n;
13             long v;
14             if ((as = counterCells) != null && (n = as.length) > 0) { // 已经初始化过了
15                 if ((a = as[(n - 1) & h]) == null) { // hash桶(cell)为空
16                     if (cellsBusy == 0) { // 并且没有争用线程
17                         CounterCell r = new CounterCell(x); // 创建一个计数单元
18                         if (cellsBusy == 0 && U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) { // 尝试占有此hash桶
19                             boolean created = false;
20                             try {
21                                 CounterCell[] rs;
22                                 int m, j;
23                                 if ((rs = counterCells) != null && (m = rs.length) > 0 && rs[j = (m - 1) & h] == null) { // 加锁后,再次检查
24                                     rs[j] = r; // 计数单元占领此桶
25                                     created = true; // 创建成功
26                                 }
27                             } finally {
28                                 cellsBusy = 0; // 释放锁
29                             }
30                             if (created) // 成功,则跳出循环
31                                 break;
32                             continue; // 否则继续循环计数
33                         }
34                     }
35                     collide = false; // 因为上次此桶还为空,暂时不考虑扩容操作
36                 } else if (!wasUncontended) // 说明有竞争,如果没有标记过,则标记为true
37                     wasUncontended = true; // 重新计算线程的hash值,寻找别的hash桶
38                 else if (U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x)) // 尝试CAS更新
39                     break; // 成功则跳出
40                 else if (counterCells != as || n >= NCPU) // 有线程已经进行了扩容,或者数组长度达到最大值(大于CPU的核心数,即线程数,已经没有扩容的必要了)
41                     collide = false; // 清除扩容意向
42                 else if (!collide) // Cell不为空,且CAS失败,标记扩容意向
43                     collide = true;
44                 else if (cellsBusy == 0 && U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) { // 尝试加锁
45                     try {
46                         if (counterCells == as) { // 扩容
47                             CounterCell[] rs = new CounterCell[n << 1]; // 2倍
48                             for (int i = 0; i < n; ++i)
49                                 rs[i] = as[i]; // 复制
50                             counterCells = rs; // 指向新数组
51                         }
52                     } finally {
53                         cellsBusy = 0; // 解锁
54                     }
55                     collide = false; // 清除扩容意向
56                     continue; // 从头继续
57                 }
58                 h = ThreadLocalRandom.advanceProbe(h); // 从新计算hash值
59             } else if (cellsBusy == 0 && counterCells == as && U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) { // 初始化
60                 boolean init = false;
61                 try { // 初始化table
62                     if (counterCells == as) {
63                         CounterCell[] rs = new CounterCell[2]; // 初始长度为2
64                         rs[h & 1] = new CounterCell(x); // 对其中一个单元进行计数操作
65                         counterCells = rs;
66                         init = true; // 初始化完成
67                     }
68                 } finally {
69                     cellsBusy = 0; // 解锁
70                 }
71                 if (init) // 成功,则跳出循环
72                     break;
73             } else if (U.compareAndSwapLong(this, BASECOUNT, v = baseCount, v + x)) // 直接加在baseCount上面
74                 break; // 成功则跳出循环,否则继续分槽计数
75         }
76     }

 

行文至此结束。

 

尊重他人的劳动,转载请注明出处:http://www.cnblogs.com/aniao/p/aniao_chm.html

posted @ 2018-04-02 01:03  林城画序  阅读(485)  评论(0编辑  收藏