zoukankan      html  css  js  c++  java
  • 【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

  • 相关阅读:
    IOS开发防止图片渲染的方法
    IOS界面通信-代理(协议)传值
    IOS打开其他应用、以及被其他应用打开
    IOS UITableView的分隔线多出问题
    self.view 的不当操作造成死循环
    IOS 导航栏属性设置
    在iOS 8及以后使用UIAlertController 等各种弹出警告通知
    iOS通过URL构建UIImage
    自定义 URL Scheme 完全指南
    Unknown type name 'NSString' 解决方案
  • 原文地址:https://www.cnblogs.com/aniao/p/aniao_chm.html
Copyright © 2011-2022 走看看