标签:eve OLE volatile 空指针 conda image out 没有 app
基于跳表,支持并发,有序的哈希表。
红色路径为寻找结点F。
拿空间换时间,时间复杂度,O(nlogn).
1 final K key; // 键 2 volatile Object value; // 值 3 volatile Node<K,V> next; // 指向下一个结点
1 Node(K key, Object value, Node<K,V> next) { // 构造方法 2 this.key = key; 3 this.value = value; 4 this.next = next; 5 } 6 7 Node(Node<K,V> next) { // 构造方法,用来构建标记结点,特点是值为自身 8 this.key = null; 9 this.value = this; 10 this.next = next; 11 }
1 boolean isBaseHeader() { // 是否为头结点(每级) 2 return value == BASE_HEADER; 3 } 4 5 boolean appendMarker(Node<K,V> f) { // 插入标记结点 6 return casNext(f, new Node<K,V>(f)); 7 } 8 9 void helpDelete(Node<K,V> b, Node<K,V> f) { // 帮助删除 10 if (f == next && this == b.next) { // 如果b和f分别是自己的前驱结点和后继结点 11 if (f == null || f.value != f) // 当前结点还没有被标记删除(后接标记结点) 12 casNext(f, new Node<K,V>(f)); // 直接删除当前结点 13 else // 如果已经标记为删除,则一次性删除当前结点后标记结点 14 b.casNext(this, f.next); 15 } 16 }
1 final Node<K,V> node; // 指向实际结点 2 final Index<K,V> down; // 指向下级索引 3 volatile Index<K,V> right; // 指向右侧索引
1 Index(Node<K,V> node, Index<K,V> down, Index<K,V> right) { // 构造方法 2 this.node = node; 3 this.down = down; 4 this.right = right; 5 }
1 final boolean indexesDeletedNode() { // 删除索引结点 2 return node.value == null; 3 } 4 5 final boolean link(Index<K,V> succ, Index<K,V> newSucc) { // 链接(右侧插入)新索引 6 Node<K,V> n = node; // 当前索引的node域 7 newSucc.right = succ; // 新索引的right域名设为当前索引的右侧索引 8 return n.value != null && casRight(succ, newSucc); // 若node结点没被删除,设置新索引到当前索引的right域 9 } 10 11 final boolean unlink(Index<K,V> succ) { // 解除当前索引的右侧索引 12 return node.value != null && casRight(succ, succ.right); // 若node结点没被删除,设置右侧索引的右侧索引到当前索引的right域 13 }
1 static final class HeadIndex<K,V> extends Index<K,V> { // 继承Index 2 final int level; // 级别 3 HeadIndex(Node<K,V> node, Index<K,V> down, Index<K,V> right, int level) { 4 super(node, down, right); 5 this.level = level; 6 } 7 }
1 private static final Object BASE_HEADER = new Object(); // 标明基础层(Node层)头节点 2 3 private transient volatile HeadIndex<K,V> head; // 最顶层头节点 4 5 final Comparator<? super K> comparator; // 比较器 6 7 private transient KeySet<K> keySet; // 键集合 8 9 private transient EntrySet<K,V> entrySet; // 键值对集合 10 11 private transient Values<V> values; // 值集合 12 13 private transient ConcurrentNavigableMap<K,V> descendingMap; // 降序(键)集合
1 public ConcurrentSkipListMap() { 2 this.comparator = null; 3 initialize(); 4 } 5 6 public ConcurrentSkipListMap(Comparator<? super K> comparator) { 7 this.comparator = comparator; 8 initialize(); 9 } 10 11 public ConcurrentSkipListMap(Map<? extends K, ? extends V> m) { 12 this.comparator = null; 13 initialize(); 14 putAll(m); // 将m中的元素加入跳表 15 } 16 17 public ConcurrentSkipListMap(SortedMap<K, ? extends V> m) { 18 this.comparator = m.comparator(); 19 initialize(); 20 buildFromSorted(m); // 根据m的元素及顺序构建跳表 21 }
1 private void initialize() { 2 keySet = null; 3 entrySet = null; 4 values = null; 5 descendingMap = null; 6 head = new HeadIndex<K, V>(new Node<K, V>(null, BASE_HEADER, null), null, null, 1); // Node.value = BASE_HEADER, 基础层(Node层)头节点 7 }
1 private V doPut(K key, V value, boolean onlyIfAbsent) { 2 3 }
1 Node<K, V> z; // 指向待插入结点 2 if (key == null) // 参数校验,键为空,抛出空指针异常 3 throw new NullPointerException(); 4 Comparator<? super K> cmp = comparator; // 比较器 5 outer: for (;;) { // 外层循环 6 for (Node<K, V> b = findPredecessor(key, cmp), n = b.next;;) { // n为当前结点,b是n的前驱结点,新结点是要插入到b和n之间的 7 if (n != null) { 8 Object v; // 指向当前结点的value 9 int c; // 比较key的结果 10 Node<K, V> f = n.next; // n的后继结点 11 if (n != b.next) // 如果数据不一致(有别的线程修改了其前驱结点的next域) 12 break; // 重新读取 13 if ((v = n.value) == null) { // 如果n被删除 14 n.helpDelete(b, f); // 去帮助删除,使其尽快结束 15 break; // 重新读取 16 } 17 if (b.value == null || v == n) // b结点被删除(其value为null,或其后继结点是marker结点) 18 break; 19 if ((c = cpr(cmp, key, n.key)) > 0) { // key大于n结点的key值,因为要插入到当前结点的前面,所以不满足要求,需要右移 20 b = n; 21 n = f; // 右移 22 continue; // 继续 23 } 24 if (c == 0) { // 键相等,替换 25 if (onlyIfAbsent || n.casValue(v, value)) { 26 @SuppressWarnings("unchecked") 27 V vv = (V) v; 28 return vv; // 返回旧值 29 } 30 break; // CAS失败,有别的线程捣乱,重来 31 } 32 } 33 34 z = new Node<K, V>(key, value, n); // 构建新结点 35 if (!b.casNext(n, z)) 36 break; // CAS失败,有别的线程捣乱,重来 37 break outer; // 成功,则跳出外层循环 38 } 39 }
1 int rnd = ThreadLocalRandom.nextSecondarySeed(); // 获取一个线程无关的随机数,int类型,32位 2 if ((rnd & 0x80000001) == 0) { // 最高位和最低位为1的情况下,除基础层新增结点外,各层均不再增索引 3 int level = 1, max; 4 while (((rnd >>>= 1) & 1) != 0) // 低位(从第2位开始)连续为1的个数,作为选取层 5 ++level; 6 Index<K, V> idx = null; // 指向从顶层开始第一个需要调整的索引,一般是选择层level,如果level大于max,说明需要新增一层,而新增的那层(level层)不需要调整(head->HeadIndex)指向它就行,所以此时,idx指向level-1层新增的索引 7 HeadIndex<K, V> h = head; // 顶层头索引 8 if (level <= (max = h.level)) { // 如果选取的层没有超出最大层 9 for (int i = 1; i <= level; ++i) //构建一个从 1 层到 level层的纵纵向索引(Index)链 10 idx = new Index<K, V>(z, idx, null); // 此时,idx指向level层新增的索引 11 } else { // 如果选取层超过了最大层,则增加一层索引 12 level = max + 1; // 此时,level为老的最大层加1 13 @SuppressWarnings("unchecked") 14 Index<K, V>[] idxs = (Index<K, V>[]) new Index<?, ?>[level + 1]; // 用长度为level+1的数组,保存各层(1到level层,数组[0]未使用,为的是索引的层数与其所在数组的下标相等)新增索引的引用 15 for (int i = 1; i <= level; ++i) 16 idxs[i] = idx = new Index<K, V>(z, idx, null); // 每层新增索引保存在对应其层数的下标位置处,idx最后指向level层新增的索引 17 for (;;) { 18 h = head; // 再次获取顶层头索引 19 int oldLevel = h.level; // 获取老的最大层 20 if (level <= oldLevel) // 如果选取层又比oldLevel小了,说明,别的线程抢先更新过跳表了 21 break; // 跳出循环,idx最后指向level层的索引,同没有超出最大层的情况 22 HeadIndex<K, V> newh = h; 23 Node<K, V> oldbase = h.node; 24 for (int j = oldLevel + 1; j <= level; ++j) // 更新新增层纵向头索引,正常情况下只新增一层 25 newh = new HeadIndex<K, V>(oldbase, newh, idxs[j], j); // newh最后指向顶层头索引 26 if (casHead(h, newh)) { // CAS head(head始终指向顶层头索引) 27 h = newh; // h也指向顶层头索引 28 idx = idxs[level = oldLevel]; // idx指向老的顶层头索引 29 break; // 跳出循环 30 } 31 } 32 }
1 splice: for (int insertionLevel = level;;) { 2 int j = h.level; 3 for (Index<K, V> q = h, r = q.right, t = idx;;) { 4 if (q == null || t == null) // 头节点被删除,或者新增索引为空,直接跳出外层循环 5 break splice; 6 if (r != null) { 7 Node<K, V> n = r.node; // 获得右索引结点 8 int c = cpr(cmp, key, n.key); // 比较key 9 if (n.value == null) { // n(正在)被删除 10 if (!q.unlink(r)) // 解除r索引 11 break; // 如果失败,说明有别的线程干预,跳出内循环,重新获取level 12 r = q.right; // 获取新的右索引 13 continue; // 继续 14 } 15 if (c > 0) { // key大于n结点的key值,需要右移 16 q = r; 17 r = r.right; // 右移 18 continue; // 继续 19 } 20 } 21 22 if (j == insertionLevel) { 23 if (!q.link(r, t)) // 将t插在q和r之间 24 break; // 如果失败,跳出内循环,重试 25 if (t.node.value == null) { // t索引指向的结点被删除 26 findNode(key); 27 break splice; // 跳出外层循环 28 } 29 if (--insertionLevel == 0) // 处理结束 30 break splice; // 跳出外层循环 31 } 32 33 if (--j >= insertionLevel && j < level) 34 t = t.down; // 处理下一层索引 35 q = q.down; // 同步更新 36 r = q.right; // 同步更新 37 } 38 }
行文至此结束。
尊重他人的劳动,转载请注明出处:http://www.cnblogs.com/aniao/p/aniao_skip.html
【JUC源码解析】ConcurrentSkipListMap
标签:eve OLE volatile 空指针 conda image out 没有 app
原文地址:https://www.cnblogs.com/aniao/p/aniao_skip.html