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;
}