简介
支持并发的哈希表。其中包括红黑树,扩容,分槽计数等知识点。
源码分析
常量
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