SkipList、ConcurrentSkipListMap和ConcurrentSkipListSet

SkipList(跳表)

    跳表(Skiplist)是一个特殊的链表,相比一般的链表,有更高的效率,平均的查找、插入、删除时间复杂度都是O(logn)。
在这里插入图片描述

查询

    例如查询5

  • 从左上角的1开始,查询1右边的10
  • 由于10>5,操作数仍然是1
  • 1下面有数据,操作数下移到第二行的1
  • 比较右边的数值 5>=5,操作数右移到第二行的5
  • 5右边的数值10>5,操作数不变
  • 5下面有数据,操作数下移到第三行的5
  • 5右边的数值8>5,操作数不变
  • 5下面没有数据,所以就返回第三行的5

添加

    例如添加13

  • 查询到最接近且不大于13的数值,就是第三行的12
  • 在12右边插入13,然后根据随机函数计算是否需要向上添加数据
  • 如果否就结束,如果需要就更改两边的数据的链表指向

删除

    例如添加12

  • 查询到12的位置
  • 将12的左右链表全部删除

ConcurrentSkipListMap和ConcurrentSkipListSet

    ConcurrentSkipListMap是是线程安全的有序的哈希表,相当于线程安全的TreeMap,key和value都不可以为空。
    ConcurrentSkipListSet相当于线程安全的TreeSet,是一个基于ConcurrentSkipListMap的可缩放并发NavigableSet实现。

数据结构

    //保存键值对的数据节点
    static final class Node<K, V> {
        final K key;
        volatile Object value;
        //后继数据节点
        volatile Node<K, V> next;
    }

    //索引节点
    static class Index<K, V> {
        //关联的数据节点
        final Node<K, V> node;
        //下一级别索引节点
        final Index<K, V> down;
        //当前索引级别中,后继索引节点
        volatile Index<K, V> right;
    }

    //索引头
    static final class HeadIndex<K, V> extends Index<K, V> {
        //索引级别
        final int level;
    }

findPredecessor

    /**
     * 返回小于且最接近给定key的数据节点
     * 如果不存在这样的数据节点就返回最低级别的索引头。
     */
    private Node<K, V> findPredecessor(Object key, Comparator<? super K> cmp) {
        if (key == null)
            throw new NullPointerException(); // don't postpone errors
        for (; ; ) {
            for (Index<K, V> q = head, r = q.right, d; ; ) {
                if (r != null) {
                    Node<K, V> n = r.node;
                    K k = n.key;
                    if (n.value == null) {
                        if (!q.unlink(r))
                            break;           // restart
                        r = q.right;         // reread r
                        continue;
                    }
                    给定key大于当前key,继续往右查找
                    if (cpr(cmp, key, k) > 0) {
                        q = r;
                        r = r.right;
                        continue;
                    }
                }
                if ((d = q.down) == null)
                    //现在已经是最低级别的数据了
                    return q.node;
                q = d;
                r = d.right;
            }
        }
    }

put

    /**
     * 如果添加的元素不存在,则插入,如果存在且onlyIfAbsent为false,则替换value。
     * 返回被替换的旧value,否则返回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 (; ; ) {
            /**
             * 返回小于且最接近给定key的数据节点
             * 如果不存在这样的数据节点就返回最低级别的索引头。
             */
            Node<K, V> b = findPredecessor(key, cmp);
            for (Node<K, V> n = b.next; ; ) {
                if (n != null) {
                    Object v;
                    int c;
                    Node<K, V> f = n.next;
                    /**
                     * 两次读取到的b的后继节点不同
                     * 说明其它线程操作了该跳表
                     */
                    if (n != b.next)               // inconsistent read
                        break;
                    //n的value为null,,说明其它线程删除了n
                    if ((v = n.value) == null) {   // n is deleted
                        n.helpDelete(b, f);
                        break;
                    }
                    //b的value为null,,说明其它线程删除了b
                    if (b.value == null || v == n) // b is deleted
                        break;
                    //要找的节点还在后面
                    if ((c = cpr(cmp, key, n.key)) > 0) {
                        b = n;
                        n = f;
                        continue;
                    }
                    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
                }
                //n为null,说明当前跳表中没有要找的Node节点,直接新建并插入节点
                z = new Node<K, V>(key, value, n);
                //添加成功,重新遍历
                if (!b.casNext(n, z))
                    break;         // restart if lost race to append to b
                break outer;
            }
        }

        int rnd = ThreadLocalRandom.nextSecondarySeed();
        //插入索引节点
        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)
                	//z是新加的节点
                    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)
                        newh = new HeadIndex<K, V>(oldbase, newh, idxs[j], j);
                    if (casHead(h, newh)) {
                        h = newh;
                        idx = idxs[level = oldLevel];
                        break;
                    }
                }
            }
            // find insertion points and splice in
            //把新添加的索引的左右都连上
            splice:
            for (int insertionLevel = level; ; ) {
                int j = h.level;
                //t是新加的索引节点的最上层
                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);
                        if (n.value == null) {
                            if (!q.unlink(r))
                                break;
                            r = q.right;
                            continue;
                        }
                        //继续右移
                        if (c > 0) {
                            q = r;
                            r = r.right;
                            continue;
                        }
                    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值