JDK源码--ConcurrentSkipListMap(跳跃表)

11 篇文章 0 订阅

原理

  • 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值