【高并发系列】23、JDK并发容器 - 随机数据结构 - 跳表 SkipList

跳表是一种可以用来快速查找的数据结构,类似平衡树,但平衡树的插入和删除很可能导致平衡树的全局调整,而跳表只需要局部调整;在高并发情况下,需为保证线程安全,对于平衡树需要一个全局锁,而对于跳表只需要部分锁即可;跳表的时间复杂度是O(log n),空间复杂度是O(n);

跳表具有如下性质:
(1) 由很多层结构组成
(2) 每一层都是一个有序的链表
(3) 最底层(Level 1)的链表包含所有元素
(4) 如果一个元素出现在 Level i 的链表中,则它在 Level i 之下的链表也都会出现。
(5) 每个节点包含两个指针,一个指向同一链表中的下一个元素,一个指向下面一层的元素。

ConcurrentSkipListMap特点:

  • 有序链表实现;
  • 无锁实现;
  • value值不能为空;
  • 层级越高跳跃性越大,数据越少,查询理论变快;
  • 新的Node是否抽出来作为Index,随机决定;
  • Index对应的value由随机数决定;
  • 每层元素,HeadIndex固定为所有Node中最小的;
  • 很多开源组件中有使用,如Level DB、Redis等;

【高并发系列】23、JDK并发容器 - 随机数据结构 - 跳表 SkipList_第1张图片

从结构上很明显,跳表是一种使用空间换时间的算法;

跳表内所有链表元素是排序的;查找时,可以从顶级链表开始,一旦发现被查找元素大于当前链表中值,转入下一层链表继续查找,因此搜索是跳跃式的;

ConcurrentSkipListMap类中关键数据结构

1、Node节点,封装Map中的key和value,以及next下一个节点,并且使用CAS方法设置当前value及next节点值;

/**
 * Nodes hold keys and values, and are singly linked in sorted
 * order, possibly with some intervening marker nodes. The list is
 * headed by a dummy node accessible as head.node. The value field
 * is declared only as Object because it takes special non-V
 * values for marker and header nodes.
 */
static final class Node {
    final K key;
    volatile Object value;
    volatile Node next;

    /**
     * compareAndSet value field
     */
    boolean casValue(Object cmp, Object val) {
        return UNSAFE.compareAndSwapObject(this, valueOffset, cmp, val);
    }

    /**
     * compareAndSet next field
     */
    boolean casNext(Node cmp, Node val) {
        return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
    }
    ...
}

2、Index,封装Node节点,并且保存向下和向右的引用;

/**
 * Index nodes represent the levels of the skip list.  Note that
 * even though both Nodes and Indexes have forward-pointing
 * fields, they have different types and are handled in different
 * ways, that can't nicely be captured by placing field in a
 * shared abstract class.
 */
static class Index {
    final Node node;
    final Index down;
    volatile Index right;

    ...
}

3、HeadIndex,链表头部第一个Index,记录当前表头处于哪一层,当前值以及向下、向右的引用;

/**
 * Nodes heading each level keep track of their level.
 */
static final class HeadIndex extends Index {
    final int level;
    HeadIndex(Node node, Index down, Index right, int level) {
        super(node, down, right);
        this.level = level;
    }
}

 

你可能感兴趣的:(Java)