目录
6、remove / replace / replaceAll / clear
ConcurrentSkipListSet是基于ConcurrentSkipListMap实现的线程安全的NavigableSet接口实现类,与之对应的线程不安全的实现类就是基于TreeMap实现的TreeSet;ConcurrentNavigableMap是基于SkipList跳跃表实现的线程安全的NavigableMap实现类,后者对应的线程不安全的实现类就是基于红黑树实现的TreeMap。本篇博客就详细探讨这两类的实现细节。
一、ConcurrentSkipListSet
ConcurrentSkipListSet的类继承关系如下:
其实现的核心接口NavigableSet的另一个典型实现类就是TreeSet,跟TreeSet基于TreeMap实现一样, ConcurrentSkipListSet的实现基于ConcurrentSkipListMap的,添加和删除元素,元素遍历等都是基于ConcurrentSkipListMap方法的,value固定为Boolean.TRUE,其常用方法实现如下:
public ConcurrentSkipListSet() {
m = new ConcurrentSkipListMap<E,Object>();
}
public ConcurrentSkipListSet(Comparator<? super E> comparator) {
m = new ConcurrentSkipListMap<E,Object>(comparator);
}
public boolean add(E e) {
return m.putIfAbsent(e, Boolean.TRUE) == null;
}
public boolean remove(Object o) {
return m.remove(o, Boolean.TRUE);
}
public Iterator<E> iterator() {
return m.navigableKeySet().iterator();
}
public Iterator<E> descendingIterator() {
return m.descendingKeySet().iterator();
}
二、ConcurrentSkipListMap
1、定义
ConcurrentSkipListMap的类继承关系如下:
从上图可知,ConcurrentNavigableMap继承自ConcurrentMap和NavigableMap,后者的典型实现类就是TreeMap,纯粹是基于红黑树实现的,可以参考《java8 TreeMap接口实现源码解析》。ConcurrentNavigableMap没有添加新的方法,只是改写了父类接口的方法定义,如下:
这些方法的用途可以参考API,会挑选其中典型的方法研究其实现细节。该类包含的属性如下:
//头索引节点
private transient volatile HeadIndex<K,V> head;
//比较大小的比较器
final Comparator<? super K> comparator;
//key视图,下面这些视图都是在请求相关方法时才会创建
private transient KeySet<K> keySet;
//键值对视图
private transient EntrySet<K,V> entrySet;
//value视图
private transient Values<V> values;
//倒序遍历的视图
private transient ConcurrentNavigableMap<K,V> descendingMap;
包含的静态常量如下:
//初始化head属性时使用,表示一个空节点
private static final Object BASE_HEADER = new Object();
private static final int EQ = 1;
private static final int LT = 2;
private static final int GT = 0; // Actually checked as !LT
包含的静态属性通过static代码块初始化,如下:
2、Node / Index / HeadIndex
这三个都是内部类,其中Node表示一个键值对,其定义如下:
static final class Node<K,V> {
//键值对的key和value
final K key;
volatile Object value;
//链表中的下一个节点
volatile Node<K,V> next;
Node(K key, Object value, Node<K,V> next) {
this.key = key;
this.value = value;
this.next = next;
}
Node(Node<K,V> next) {
this.key = null;
this.value = this;
this.next = next;
}
//cas修改value
boolean casValue(Object cmp, Object val) {
return UNSAFE.compareAndSwapObject(this, valueOffset, cmp, val);
}
//cas修改next
boolean casNext(Node<K,V> cmp, Node<K,V> val) {
return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
}
boolean isMarker() {
return value == this;
}
boolean isBaseHeader() {
return value == BASE_HEADER;
}
//插入一个value指向自己的节点,next为f的节点
//删除某个节点时会将其value置为null,然后调用此方法在该节点后插入一个marker,将该节点从next链表中移除
//marker在这里是打一个标识同时保存下一个节点的引用,保证将其从next链表中移除失败,即cas修改前一个节点的next属性失败的情形下该节点可以被正常移除
boolean appendMarker(Node<K,V> f) {
return casNext(f, new Node<K,V>(f));
}
//在查询或者修改节点时,发现某个节点的value已经是null了,会调用此方法
//b是前一个节点,f是next节点
void helpDelete(Node<K,V> b, Node<K,V> f) {
if (f == next && this == b.next) {
//再次检查链表关系
if (f == null || f.value != f)
//该节点未插入marker节点,此处重新插入,下次调用时进入else分支
casNext(f, new Node<K,V>(f));
else
//f是一个marker节点
//将this和f都从链表中移除
b.casNext(this, f.next);
}
}
V getValidValue() {
Object v = value;
if (v == this || v == BASE_HEADER) //value是无效
return null;
@SuppressWarnings("unchecked") V vv = (V)v;
return vv;
}
AbstractMap.SimpleImmutableEntry<K,V> createSnapshot() {
Object v = value;
if (v == null || v == this || v == BASE_HEADER) //value是无效
return null;
@SuppressWarnings("unchecked") V vv = (V)v;
return new AbstractMap.SimpleImmutableEntry<K,V>(key, vv);
}
//获取属性偏移量
private static final sun.misc.Unsafe UNSAFE;
private static final long valueOffset;
private static final long nextOffset;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> k = Node.class;
valueOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("value"));
nextOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("next"));
} catch (Exception e) {
throw new Error(e);
}
}
}
Index是HeadIndex的父类,都表示SkipList中的索引节点,其实现如下:
static class Index<K,V> {
//关联的node节点
final Node<K,V> node;
//down指向的节点的node和当前节点的node是同一个,但是down节点位于下一个层级,层级越往下包含的节点数越多,最底层包含了所有的node节点
final Index<K,V> down;
//right指向的节点的key大于当前节点,跟当前节点位于同一个层级,沿着right属性构成的链表遍历,node的key值越来越大
volatile Index<K,V> right; ,
Index(Node<K,V> node, Index<K,V> down, Index<K,V> right) {
this.node = node;
this.down = down;
this.right = right;
}
//cas修改right属性
final boolean casRight(Index<K,V> cmp