目录
2、higher / lower /ceiling / floor
4、pollFirstEntry / pollLastEntry
5、keySet / descendingKeySet / Iter
6、tailMap / headMap / subMap /SubMap
本篇博客继续上一篇《Java8 ConcurrentSkipListMap与ConcurrentSkipListSet (一) 源码解析》讲解ConcurrentNavigableMap相关方法的实现细节。
1、compute / merge
compute一共有三个方法,compute、computeIfAbsent和computeIfPresent,这四个方法的实现类似,都是先找到目标key,然后用remappingFunction计算结果,方法含义跟ConcurrentHashMap中一样的,不再赘述。
public V compute(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
if (key == null || remappingFunction == null)
throw new NullPointerException();
for (;;) {
Node<K,V> n; Object v; V r;
if ((n = findNode(key)) == null) { //没有找到目标节点
if ((r = remappingFunction.apply(key, null)) == null) //计算返回null,跳出循环返回null
break;
if (doPut(key, r, true) == null) //r不为null,插入新节点,doPut返回值不是null,则重新for循环,进入下面的else if分支
return r;
}
else if ((v = n.value) != null) { //找到目标节点,如果value为null,下一次循环findNode会将该节点删除
@SuppressWarnings("unchecked") V vv = (V) v;
if ((r = remappingFunction.apply(key, vv)) != null) { //r不为null,修改value
if (n.casValue(vv, r)) //cas失败,则再次for循环
return r;
}
else if (doRemove(key, vv) != null) //r为null,删除节点
break;
}
}
return null;
}
public V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction) {
if (key == null || mappingFunction == null)
throw new NullPointerException();
V v, p, r;
if ((v = doGet(key)) == null && //目标key不存在
(r = mappingFunction.apply(key)) != null) //计算结果非空
v = (p = doPut(key, r, true)) == null ? r : p;
return v;
}
public V computeIfPresent(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
if (key == null || remappingFunction == null)
throw new NullPointerException();
Node<K,V> n; Object v;
while ((n = findNode(key)) != null) { //目标key 存在且value非空
if ((v = n.value) != null) {
@SuppressWarnings("unchecked") V vv = (V) v;
V r = remappingFunction.apply(key, vv);
if (r != null) { //r不为null,修改value
if (n.casValue(vv, r))
return r;
}
else if (doRemove(key, vv) != null) //r为null,删除节点
break;
}
}
return null;
}
public V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
if (key == null || value == null || remappingFunction == null)
throw new NullPointerException();
for (;;) {
Node<K,V> n; Object v; V r;
if ((n = findNode(key)) == null) { //没有匹配的key,插入新节点
if (doPut(key, value, true) == null)
return value;
}
else if ((v = n.value) != null) { //找到目标key
@SuppressWarnings("unchecked") V vv = (V) v;
if ((r = remappingFunction.apply(vv, value)) != null) { //r不为null,修改value
if (n.casValue(vv, r))
return r;
}
else if (doRemove(key, vv) != null) //r为null,删除节点
return null;
}
}
}
2、higher / lower /ceiling / floor
这四个,每个都有两个方法,如ceilingKey和ceilingEntry,前者返回Key,后者返回一个Map.Entry键值对,总共8个方法;其中higher和lower相对,lower表示获取小于key的最大节点,higher表示获取大于key的最小节点;ceiling 与 floor相对,floor表示获取小于或者等于key的最大节点,ceiling 表示获取大于或者等于key的最小节点,其实现如下:
public Map.Entry<K,V> lowerEntry(K key) {
//找到小于key的最大节点
return getNear(key, LT);
}
public K lowerKey(K key) {
Node<K,V> n = findNear(key, LT, comparator);
return (n == null) ? null : n.key;
}
public Map.Entry<K,V> higherEntry(K key) {
//找到大于key的最小节点
return getNear(key, GT);
}
public K higherKey(K key) {
Node<K,V> n = findNear(key, GT, comparator);
return (n == null) ? null : n.key;
}
public Map.Entry<K,V> floorEntry(K key) {
//找到小于或者等于key的最大节点
return getNear(key, LT|EQ);
}
public K floorKey(K key) {
Node<K,V> n = findNear(key, LT|EQ, comparator);
return (n == null) ? null : n.key;
}
public Map.Entry<K,V> ceilingEntry(K key) {
//找到大于或者等于key的最小节点
return getNear(key, GT|EQ);
}
public K ceilingKey(K key) {
Node<K,V> n = findNear(key, GT|EQ, comparator);
return (n == null) ? null : n.key;
}
//rel是一个常量
final Node<K,V> findNear(K key, int rel, Comparator<? super K> cmp) {
if (key == null)
throw new NullPointerException();
for (;;) {
//找到最底层中接近key且小于key的节点b,然后往后遍历
for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
Object v;
if (n == null) //遍历万彩城
return ((rel & LT) == 0 //rel的操作就是GT,大于
|| b.isBaseHeader()) ? null : b;
Node<K,V> f = n.next;
if (n != b.next) //next节点变了,重新读取b
break;
if ((v = n.value) == null) { //n被删除了
n.helpDelete(b, f);
break;
}
if (b.value == null || v == n) //b被删除了
break;
int c = cpr(cmp, key, n.key);
if ((c == 0 && (rel & EQ) != 0) || //rel中包括EQ等于,即EQ表示找到key值相等的节点
(c < 0 && (rel & LT) == 0)) // rel中包括EQ或者GT,即GT|EQ表示大于等于key的最小节点
return n;
if ( c <= 0 && (rel & LT) != 0) //rel中包括LT,即LT表示小于等于key的最大节点
return b.isBaseHeader() ? null : b;
b = n;
n = f;
}
}
}
final AbstractMap.SimpleImmutableEntry<K,V> getNear(K key, int rel) {
Comparator<? super K> cmp = comparator;
for (;;) {
Node<K,V> n = findNear(key, rel, cmp);
if (n == null)
return null;
//根据key和value创建一个键值对
AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
if (e != null)
return e;
}
}
3、first / last
每个也是有两个方法,firstKey和firstEntry,lastKey和lastEntry,底层实现分别基于findFirst和findLast,其中findFirst很简单,head.node.next就是第一个节点,findLast比较麻烦,从head开始先往右遍历到最后然后进入下一个层级继续往右遍历,一直遍历到最底层Node节点的最右边的节点,这期间如果发现某个节点被删除了,还需要重新读取head,从头遍历一遍。其实现如下:
public K firstKey() {
//获取第一个节点
Node<K,V> n = findFirst();
if (n == null)
throw new NoSuchElementException();
return n.key;
}
public Map.Entry<K,V> firstEntry() {
for (;;) {
Node<K,V> n = findFirst();
if (n == null)
return null;
AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
if (e != null)
return e;
}
}
public K lastKey() {
//获取最后一个节点
Node<K,V> n = findLast();
if (n == null)
throw new NoSuchElementException();
return n.key;
}
public Map.Entry<K,V> lastEntry() {
for (;;) {
Node<K,V> n = findLast();
if (n == null)
return null;
AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
if (e != null)
return e;
}
}
final Node<K,V> findFirst() {
for (Node<K,V> b, n;;) {
if ((n = (b = head.node).next) == null) //head.node.next为null,空链表,返回null
return null;
if (n.value != null)
return n;
//n.value为null,删除该节点
n.helpDelete(b, n.next);
}
}
final Node<K,V> findLast() {
Index<K,V> q = head;
for (;;) {
Index<K,V> d, r;
if ((r = q.right) != null) { //right节点不为空,则沿着right属性一直向右遍历
if (r.indexesDeletedNode()) {//如果所引用的节点被删除了,将其从right链表中移除
q.unlink(r);
q = head; //重新读取head,从头开始,因为删除节点后可能导致层级变了
}
else
q = r;
} else if ((d = q.down) != null) { //right节点为空,进入下一个层级,继续往右遍历
q = d;
} else {
//down节点为空,遍历到最底层的Node节点了,通过next一直往后遍历到最后
for (Node<K,V> b = q.node, n = b.next;;) {
if (n == null)
return b.isBaseHeader() ? null : b;
Node<K,V> f = n.next;
if (n != b.next) //b的next节点变了,重读读取b
break;
Object v = n.value;
if (v == null) { // n被删除了
n.helpDelete(b, f);
break;
}
if (b.value == null || v == n) //b被删除了
break;
b = n;
n = f;
}
q = head; //上面因为节点被删除后终止for循环,会进入此代码,重新读取head
}
}
}
4、pollFirstEntry / pollLastEntry
这两个方法分别用于移除并返回第一个节点和最后一个节点,其查找第一个节点和最后一个节点的逻辑和上面的findFirst和findLast是基本一致的。
public Map.Entry<K,V> pollFirstEntry() {
return doRemoveFirstEntry();
}
public Map.Entry<K,V> pollLastEntry() {
return doRemoveLastEntry();
}
private Map.Entry<K,V> doRemoveFirstEntry() {
for (Node<K,V> b, n;;) {
if ((n = (b = head.node).next) == null) //空链表
return null;
Node<K,V> f = n.next;
if (n != b.next) //next节点变了,重新读取b
continue;
Object v = n.value;
if (v == null) { //n被删除了
n.helpDelete(b, f);
continue;
}
if (!n.casValue(v, null)) //修改为null失败,重试
continue;
if (!n.appendMarker(f) || !b.casNext(n, f)) //插入marker,将n移除,通常第二个可能会失败
findFirst(); // findFirst的逻辑和上面的for循环的逻辑是一致的,此时也可以continue的
clearIndexToFirst();
@SuppressWarnings("unchecked") V vv = (V)v;
return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, vv);
}
}
private Map.Entry<K,V> doRemoveLastEntry() {
for (;;) {
//从head往右再往下遍历找到最底层的节点为止,此时该节点还不是最后一个节点
Node<K,V> b = findPredecessorOfLast();
Node<K,V> n = b.next; //获取b的下一个节点
if (n == null) { //
if (b.isBaseHeader()) //链表是空的
return null;
else
continue; //b的next节点空了,b应该是最后一个节点了,重新遍历找到前一个节点
}
for (;;) {
Node<K,V> f = n.next;
if (n != b.next) //next节点变了,重新读取b
break;
Object v = n.value;
if (v == null) { //n被删除了
n.helpDelete(b, f);
break;
}
if (b.value == null || v == n) //b被删除了
break;
if (f != null) { //n还有后继节点,继续往后遍历
b = n;
n = f;
continue;
}
//f为null,此时n就是最后一个节点了,将value置为null
if (!n.casValue(v, null))
break; //修改失败,可能该节点被删除了,则重新开始
K key = n.key;
//删除节点n
if (!n.appendMarker(f) || !b.casNext(n, f))
findNode(key); //失败后,通过findNode清除节点n和对应的索引节点
else { //删除节点n成功,通过findPredecessor删除对应的索引节点
findPredecessor(key, comparator);
if (head.right == null)
tryReduceLevel(); //尝试降低层级
}
@SuppressWarnings("unchecked") V vv = (V)v;
return new AbstractMap.SimpleImmutableEntry<K,V>(key, vv); //返回键值对
}
}
}
//清除指向第一个节点的索引节点
private void clearIndexToFirst() {
for (;;) {
for (Index<K,V> q = head;;) {
Index<K,V> r = q.right; //q.right就是第一个节点的索引节点了
if (r != null && r.indexesDeletedNode() //r不为空且所引用的节点被删除了
&& !q.unlink(r)) //将r从q的right链表中移除失败,则重试,可能其他线程在并行删除
break;
if ((q = q.down) == null) { //处理下一个层级的索引节点
//如果到最底层了
if (head.right == null) //尝试降低层级
tryReduceLevel();
return;
}
}
}
}
//从head开始一直往下查找到最底层为止
private Node<K,V> findPredecessorOfLast() {
for (;;) {
for (Index<K,V> q = head;;) {
Index<K,V> d, r;
if ((r = q.right) != null) {
if (r.indexesDeletedNode()) { //r被删除了
q.unlink(r);
break; // must restart
}
//r所引用的节点还有下一个节点,遍历下一个right节点
if (r.node.next != null) {
q = r;
continue;
}
}
//right节点为null,遍历下一个层级的节点
if ((d = q.down) != null)
q = d;
else
//遍历到底层了
return q.node;
}
}
}
5、keySet / descendingKeySet / Iter
这两个方法用来遍历当前Map中的key,前者是顺序遍历,后者是倒序遍历,其实现如下:
public NavigableSet<K> keySet() {
KeySet<K> ks = keySetView;
return (ks != null) ? ks : (keySetView = new KeySet<K>(this));
}
public NavigableSet<K> descendingKeySet() {
return descendingMap().navigableKeySet();
}
public ConcurrentNavigableMap<K,V> descendingMap() {
ConcurrentNavigableMap<K,V> dm = descendingMap;
return (dm != null) ? dm : (descendingMap = new SubMap<K,V>
(this, null, false, null, false, true));
}
内部类SubMap的实现下一节会讲解,重点关注内部类KeySet的实现,该类实现了NavigableSet接口,不过其接口实现都是基于保存的ConcurrentNavigableMap引用,如下图:
重点关注其遍历方法的实现,如下:
public Iterator<E> iterator() {
if (m instanceof ConcurrentSkipListMap)
return ((ConcurrentSkipListMap<E,Object>)m).keyIterator();
else
//KeySet类也适用于内部类SubMap的
return ((ConcurrentSkipListMap.SubMap<E,Object>)m).keyIterator();
}
Iterator<K> keyIterator() {
return new KeyIterator();
}
其中KeyIterator继承自内部类Iter,该类的类继承关系如下:
三个子类分别用于遍历key,value和键值对Entry, KeyIterator和Itrer的实现如下:
final class KeyIterator extends Iter<K> {
public K next() {
Node<K,V> n = next;
advance(); //获取下一个节点
//不同的子类就是此处返回值不一样
return n.key;
}
}
abstract class Iter<T> implements Iterator<T> {
/** 上一次next方法返回的节点 */
Node<K,V> lastReturned;
/** 下一次next方法返回的节点 */
Node<K,V> next;
/** 下一次next方法返回的value */
V nextValue;
/** Initializes ascending iterator for entire range. */
Iter() {
while ((next = findFirst()) != null) { //找到第一个节点
Object x = next.value;
if (x != null && x != next) { //校验x是否正常节点
@SuppressWarnings("unchecked") V vv = (V)x;
nextValue = vv;
break;
}
}
}
public final boolean hasNext() {
return next != null;
}
/** Advances next to higher entry. */
final void advance() {
if (next == null)
throw new NoSuchElementException();
lastReturned = next;
while ((next = next.next) != null) { //通过next属性找到下一个节点
Object x = next.value;
if (x != null && x != next) { //校验x是否有效节点
@SuppressWarnings("unchecked") V vv = (V)x;
nextValue = vv;
break;
}
}
}
public void remove() {
Node<K,V> l = lastReturned;
if (l == null)
throw new IllegalStateException();
//移除目标节点
ConcurrentSkipListMap.this.remove(l.key);
lastReturned = null;
}
}
6、tailMap / headMap / subMap /SubMap
上述三个方法都是返回基于当前Map的指定返回的子Map,tailMap返回大于某个key的子Map,headMap 表示小于某个key的子Map,subMap表示返回在两个key之间的子Map。每个方法都有一个重载版本,可以指定是否包含起始值或者终止值,其底层实现都是内部类SubMap,如下:
public ConcurrentNavigableMap<K,V> tailMap(K fromKey) {
return tailMap(fromKey, true);
}
public ConcurrentNavigableMap<K,V> tailMap(K fromKey,
boolean inclusive) {
if (fromKey == null)
throw new NullPointerException();
return new SubMap<K,V>
(this, fromKey, inclusive, null, false, false);
}
public ConcurrentNavigableMap<K,V> headMap(K toKey) {
return headMap(toKey, false);
}
public ConcurrentNavigableMap<K,V> headMap(K toKey,
boolean inclusive) {
if (toKey == null)
throw new NullPointerException();
return new SubMap<K,V>
(this, null, false, toKey, inclusive, false);
}
public ConcurrentNavigableMap<K,V> subMap(K fromKey, K toKey) {
return subMap(fromKey, true, toKey, false);
}
public ConcurrentNavigableMap<K,V> subMap(K fromKey,
boolean fromInclusive,
K toKey,
boolean toInclusive) {
if (fromKey == null || toKey == null)
throw new NullPointerException();
return new SubMap<K,V>
(this, fromKey, fromInclusive, toKey, toInclusive, false);
}
SubMap也是需要实现ConcurrentNavigableMap接口,大部分方法的实现还是基于父Map的,其包含的属性如下:
/** 关联的父Map*/
private final ConcurrentSkipListMap<K,V> m;
/**起始key */
private final K lo;
/**终止key*/
private final K hi;
/** 是否包含起始key */
private final boolean loInclusive;
/** 是否包含终止key */
private final boolean hiInclusive;
/** 是否倒序遍历 */
private final boolean isDescending;
//惰性初始化的视图
private transient KeySet<K> keySetView;
private transient Set<Map.Entry<K,V>> entrySetView;
private transient Collection<V> valuesView;
重点关注其遍历方法的实现,如下:
Iterator<K> keyIterator() {
return new SubMapKeyIterator();
}
Iterator<V> valueIterator() {
return new SubMapValueIterator();
}
Iterator<Map.Entry<K,V>> entryIterator() {
return new SubMapEntryIterator();
}
final class SubMapValueIterator extends SubMapIter<V> {
public V next() {
V v = nextValue;
advance(); //获取下一个遍历的节点
return v;
}
public int characteristics() {
return 0;
}
}
final class SubMapKeyIterator extends SubMapIter<K> {
public K next() {
Node<K,V> n = next;
advance(); //获取下一个遍历的节点
return n.key;
}
public int characteristics() {
return Spliterator.DISTINCT | Spliterator.ORDERED |
Spliterator.SORTED;
}
public final Comparator<? super K> getComparator() {
return SubMap.this.comparator();
}
}
final class SubMapEntryIterator extends SubMapIter<Map.Entry<K,V>> {
public Map.Entry<K,V> next() {
Node<K,V> n = next;
V v = nextValue;
advance(); //获取下一个遍历的节点
return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
}
public int characteristics() {
return Spliterator.DISTINCT;
}
}
父类SubMapIter的实现如下:
abstract class SubMapIter<T> implements Iterator<T>, Spliterator<T> {
Node<K,V> lastReturned //上一次next方法返回的节点
Node<K,V> next; //下一次next方法返回的节点
V nextValue; //下一次next方法返回的value
SubMapIter() {
Comparator<? super K> cmp = m.comparator;
for (;;) {
//获取遍历的起始节点
next = isDescending ? hiNode(cmp) : loNode(cmp);
if (next == null)
break;
Object x = next.value;
if (x != null && x != next) { //x是有效节点
if (! inBounds(next.key, cmp)) //再次检查是否在指定范围内通常在
next = null;
else {
@SuppressWarnings("unchecked") V vv = (V)x;
nextValue = vv;
}
break;
}
}
}
public final boolean hasNext() {
return next != null;
}
final void advance() {
if (next == null)
throw new NoSuchElementException();
lastReturned = next;
if (isDescending)
descend();
else
ascend();
}
//顺序遍历时获取下一个节点即可
private void ascend() {
Comparator<? super K> cmp = m.comparator;
for (;;) {
next = next.next;
if (next == null)
break;
Object x = next.value;
if (x != null && x != next) { //判断next节点是否有效
if (tooHigh(next.key, cmp)) //如果超过限制则置为null
next = null;
else {
@SuppressWarnings("unchecked") V vv = (V)x;
nextValue = vv;
}
break;
}
}
}
//倒序遍历
private void descend() {
Comparator<? super K> cmp = m.comparator;
for (;;) {
//获取小于上一次节点的最大节点
next = m.findNear(lastReturned.key, LT, cmp);
if (next == null)
break;
Object x = next.value;
if (x != null && x != next) {
if (tooLow(next.key, cmp)) //校验是否低于最低值,如果是则置为null
next = null;
else {
@SuppressWarnings("unchecked") V vv = (V)x;
nextValue = vv;
}
break;
}
}
}
public void remove() {
Node<K,V> l = lastReturned;
if (l == null)
throw new IllegalStateException();
m.remove(l.key); //移除节点
lastReturned = null;
}
//Spliterator的接口实现
public Spliterator<T> trySplit() {
return null;
}
public boolean tryAdvance(Consumer<? super T> action) {
if (hasNext()) {
action.accept(next());
return true;
}
return false;
}
public void forEachRemaining(Consumer<? super T> action) {
while (hasNext())
action.accept(next());
}
public long estimateSize() {
return Long.MAX_VALUE;
}
}
//获取起始遍历节点
ConcurrentSkipListMap.Node<K,V> loNode(Comparator<? super K> cmp) {
if (lo == null) //未指定起始节点
return m.findFirst();
else if (loInclusive)
return m.findNear(lo, GT|EQ, cmp); //获取大于等于lo的最小的节点
else
return m.findNear(lo, GT, cmp);
}
//获取遍历结束节点
ConcurrentSkipListMap.Node<K,V> hiNode(Comparator<? super K> cmp) {
if (hi == null)
return m.findLast();
else if (hiInclusive)
return m.findNear(hi, LT|EQ, cmp); /获取小于等于ho的最大的节点
else
return m.findNear(hi, LT, cmp);
}
//是否在指定的范围内
boolean inBounds(Object key, Comparator<? super K> cmp) {
return !tooLow(key, cmp) && !tooHigh(key, cmp);
}
boolean tooLow(Object key, Comparator<? super K> cmp) {
int c;
return (lo != null && ((c = cpr(cmp, key, lo)) < 0 ||
(c == 0 && !loInclusive)));
}
boolean tooHigh(Object key, Comparator<? super K> cmp) {
int c;
return (hi != null && ((c = cpr(cmp, key, hi)) > 0 ||
(c == 0 && !hiInclusive)));
}
通过上述代码可知,顺序遍历是很容易的,倒序遍历时因为没有保存对前一个节点的引用,需要从head节点开始重新查找,比较耗时。