JDKソース--ConcurrentSkipListMap(ジャンプテーブル)

44997 ワード

げんり
  • Redis秩序化集合で使用され,赤黒樹と同じ時間効率を達成したが,より簡単に実現した.

  • データの読み込み
    private V doGet(Object key) {
        if (key == null)
            throw new NullPointerException();
        Comparator<? super K> cmp = comparator;
        //        ,                ,            。
        outer: for (;;) {
        	//  key         //b     key   ,  head
            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
                Object v; int c;
                //            ,      ,  null
                if (n == null)
                    break outer;
                Node<K,V> f = n.next;
                //b            ,  (       )
                if (n != b.next)                // inconsistent read
                    break;
                //      null,           ,         。
                if ((v = n.value) == null) {    // n is deleted
                    n.helpDelete(b, f);
                    break;
                }
                //          ,  
                if (b.value == null || v == n)  // b is deleted
                    break;
                //    key      ,        (n.value)
                if ((c = cpr(cmp, key, n.key)) == 0) {
                    @SuppressWarnings("unchecked") V vv = (V)v;
                    return vv;
                }
                //        key,    key     ,  
                if (c < 0)
                    break outer;
                //      ,    
                b = n;
                n = f;
            }
        }
        return null;
    }
    

    データの書き込み
    //     ,           ,         null
    private V doPut(K key, V value, boolean onlyIfAbsent) {
        Node<K,V> z;             // added node
        if (key == null)
            throw new NullPointerException();
        Comparator<? super K> cmp = comparator;
        outer: for (;;) {
            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
                if (n != null) {
                    Object v; int c;
                    Node<K,V> f = n.next;
                    if (n != b.next)               // inconsistent read
                        break;
                    if ((v = n.value) == null) {   // n is deleted
                        n.helpDelete(b, f);
                        break;
                    }
                    if (b.value == null || v == n) // b is deleted
                        break;
                    //      key,           
                    if ((c = cpr(cmp, key, n.key)) > 0) {
                        b = n;
                        n = f;
                        continue;
                    }
                    //    key    ,       (CAS)
                    if (c == 0) {
                        if (onlyIfAbsent || n.casValue(v, value)) {
                            @SuppressWarnings("unchecked") V vv = (V)v;
                            return vv;
                        }
                        break; // restart if lost race to replace value
                    }
                    // else c < 0; fall through
                }
    			//       key   ,               
                z = new Node<K,V>(key, value, n);
                //  CAS     ,         
                if (!b.casNext(n, z))
                    break;         // restart if lost race to append to b
                break outer;
            }
        }
    
    	//         (           )
        int rnd = ThreadLocalRandom.nextSecondarySeed();
        // 1/4       
        if ((rnd & 0x80000001) == 0) { // test highest and lowest bits
            int level = 1, max;
            //      
            while (((rnd >>>= 1) & 1) != 0)
                ++level;
            Index<K,V> idx = null;
            HeadIndex<K,V> h = head;
            //         ,                         
            if (level <= (max = h.level)) {
                for (int i = 1; i <= level; ++i) //???
                    idx = new Index<K,V>(z, idx, null);
            }
            //      
            else { // try to grow by one level
                level = max + 1; // hold in array and later pick the one to use
                @SuppressWarnings("unchecked")Index<K,V>[] idxs =
                    (Index<K,V>[])new Index<?,?>[level+1];
                for (int i = 1; i <= level; ++i) //      
                    idxs[i] = idx = new Index<K,V>(z, idx, null);
                for (;;) {
                    h = head;
                    int oldLevel = h.level;
                    if (level <= oldLevel) // lost race to add level
                        break;
                    HeadIndex<K,V> newh = h;
                    Node<K,V> oldbase = h.node;
                    for (int j = oldLevel+1; j <= level; ++j) //     head  
                        newh = new HeadIndex<K,V>(oldbase, newh, idxs[j], j);
                    if (casHead(h, newh)) { //  head  
                        h = newh;
                        idx = idxs[level = oldLevel];
                        break;
                    }
                }
            }
            //  
            splice: for (int insertionLevel = level;;) {
                int j = h.level;
                for (Index<K,V> q = h, r = q.right, t = idx;;) {
                    if (q == null || t == null)
                        break splice;
                    if (r != null) {
                        Node<K,V> n = r.node;
                        // compare before deletion check avoids needing recheck
                        int c = cpr(cmp, key, n.key);
                        //q   right  value    ,q   r   ,   q  right   r                   if (n.value == null) {
                            if (!q.unlink(r))
                                break;
                            r = q.right;
                            continue;
                        }
                        //right   key ,     
                        if (c > 0) {
                            q = r;
                            r = r.right;
                            continue;
                        }
                    }
    				//  right   >= key
                    if (j == insertionLevel) {
                        if (!q.link(r, t))
                            break; // restart
                        if (t.node.value == null) {
                            findNode(key);
                            break splice;
                        }
                        if (--insertionLevel == 0)
                            break splice;
                    }
    
                    if (--j >= insertionLevel && j < level)
                        t = t.down;
                    q = q.down;
                    r = q.right;
                }
            }
        }
        return null;
    }
    

    データの削除
    final V doRemove(Object key, Object value) {
        if (key == null)
            throw new NullPointerException();
        Comparator<? super K> cmp = comparator;
        outer: for (;;) {
        	//b     key   ,  head
            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
                Object v; int c;
                if (n == null) //     null,     ,    
                    break outer;
                Node<K,V> f = n.next;
                //     ,  
                if (n != b.next)                    // inconsistent read
                    break;
                //      ,  
                if ((v = n.value) == null) {        // n is deleted
                    n.helpDelete(b, f);
                    break;
                }
                if (b.value == null || v == n)      // b is deleted
                    break;
                //      key,     ,  
                if ((c = cpr(cmp, key, n.key)) < 0)
                    break outer;
                //        key,    
                if (c > 0) {
                    b = n;
                    n = f;
                    continue;
                }
                //value        ,    
                if (value != null && !value.equals(v))
                    break outer;
                //CAS      null
                if (!n.casValue(v, null))
                    break;
                if (!n.appendMarker(f) || !b.casNext(n, f))
                    findNode(key);                  // retry via findNode
                else {
                    findPredecessor(key, cmp);      // clean index
                    if (head.right == null)
                        tryReduceLevel();
                }
                @SuppressWarnings("unchecked") V vv = (V)v;
                return vv;
            }
        }
        return null;
    }