Java多线程系列--“JUC集合”05之 ConcurrentSkipListMap
来源:互联网 发布:php构架师是什么 编辑:程序博客网 时间:2024/05/24 06:08
概要
本章对Java.util.concurrent包中的ConcurrentSkipListMap类进行详细的介绍。内容包括:
ConcurrentSkipListMap介绍
ConcurrentSkipListMap原理和数据结构
ConcurrentSkipListMap函数列表
ConcurrentSkipListMap源码分析(JDK1.7.0_40版本)
ConcurrentSkipListMap示例
转载请注明出处:http://www.cnblogs.com/skywang12345/p/3498556.html
ConcurrentSkipListMap介绍
ConcurrentSkipListMap是线程安全的有序的哈希表,适用于高并发的场景。
ConcurrentSkipListMap和TreeMap,它们虽然都是有序的哈希表。但是,第一,它们的线程安全机制不同,TreeMap是非线程安全的,而ConcurrentSkipListMap是线程安全的。第二,ConcurrentSkipListMap是通过跳表实现的,而TreeMap是通过红黑树实现的。
关于跳表(Skip List),它是平衡树的一种替代的数据结构,但是和红黑树不相同的是,跳表对于树的平衡的实现是基于一种随机化的算法的,这样也就是说跳表的插入和删除的工作是比较简单的。
ConcurrentSkipListMap原理和数据结构
ConcurrentSkipListMap的数据结构,如下图所示:
说明:
先以数据“7,14,21,32,37,71,85”序列为例,来对跳表进行简单说明。
跳表分为许多层(level),每一层都可以看作是数据的索引,这些索引的意义就是加快跳表查找数据速度。每一层的数据都是有序的,上一层数据是下一层数据的子集,并且第一层(level 1)包含了全部的数据;层次越高,跳跃性越大,包含的数据越少。
跳表包含一个表头,它查找数据时,是从上往下,从左往右进行查找。现在“需要找出值为32的节点”为例,来对比说明跳表和普遍的链表。
情况1:链表中查找“32”节点
路径如下图1-02所示:
需要4步(红色部分表示路径)。
情况2:跳表中查找“32”节点
路径如下图1-03所示:
忽略索引垂直线路上路径的情况下,只需要2步(红色部分表示路径)。
下面说说Java中ConcurrentSkipListMap的数据结构。
(01) ConcurrentSkipListMap继承于AbstractMap类,也就意味着它是一个哈希表。
(02) Index是ConcurrentSkipListMap的内部类,它与“跳表中的索引相对应”。HeadIndex继承于Index,ConcurrentSkipListMap中含有一个HeadIndex的对象head,head是“跳表的表头”。
(03) Index是跳表中的索引,它包含“右索引的指针(right)”,“下索引的指针(down)”和“哈希表节点node”。node是Node的对象,Node也是ConcurrentSkipListMap中的内部类。
ConcurrentSkipListMap函数列表
// 构造一个新的空映射,该映射按照键的自然顺序进行排序。ConcurrentSkipListMap()// 构造一个新的空映射,该映射按照指定的比较器进行排序。ConcurrentSkipListMap(Comparator<? super K> comparator)// 构造一个新映射,该映射所包含的映射关系与给定映射包含的映射关系相同,并按照键的自然顺序进行排序。ConcurrentSkipListMap(Map<? extends K,? extends V> m)// 构造一个新映射,该映射所包含的映射关系与指定的有序映射包含的映射关系相同,使用的顺序也相同。ConcurrentSkipListMap(SortedMap<K,? extends V> m)// 返回与大于等于给定键的最小键关联的键-值映射关系;如果不存在这样的条目,则返回 null。Map.Entry<K,V> ceilingEntry(K key)// 返回大于等于给定键的最小键;如果不存在这样的键,则返回 null。K ceilingKey(K key)// 从此映射中移除所有映射关系。void clear()// 返回此 ConcurrentSkipListMap 实例的浅表副本。ConcurrentSkipListMap<K,V> clone()// 返回对此映射中的键进行排序的比较器;如果此映射使用键的自然顺序,则返回 null。Comparator<? super K> comparator()// 如果此映射包含指定键的映射关系,则返回 true。boolean containsKey(Object key)// 如果此映射为指定值映射一个或多个键,则返回 true。boolean containsValue(Object value)// 返回此映射中所包含键的逆序 NavigableSet 视图。NavigableSet<K> descendingKeySet()// 返回此映射中所包含映射关系的逆序视图。ConcurrentNavigableMap<K,V> descendingMap()// 返回此映射中所包含的映射关系的 Set 视图。Set<Map.Entry<K,V>> entrySet()// 比较指定对象与此映射的相等性。boolean equals(Object o)// 返回与此映射中的最小键关联的键-值映射关系;如果该映射为空,则返回 null。Map.Entry<K,V> firstEntry()// 返回此映射中当前第一个(最低)键。K firstKey()// 返回与小于等于给定键的最大键关联的键-值映射关系;如果不存在这样的键,则返回 null。Map.Entry<K,V> floorEntry(K key)// 返回小于等于给定键的最大键;如果不存在这样的键,则返回 null。K floorKey(K key)// 返回指定键所映射到的值;如果此映射不包含该键的映射关系,则返回 null。V get(Object key)// 返回此映射的部分视图,其键值严格小于 toKey。ConcurrentNavigableMap<K,V> headMap(K toKey)// 返回此映射的部分视图,其键小于(或等于,如果 inclusive 为 true)toKey。ConcurrentNavigableMap<K,V> headMap(K toKey, boolean inclusive)// 返回与严格大于给定键的最小键关联的键-值映射关系;如果不存在这样的键,则返回 null。Map.Entry<K,V> higherEntry(K key)// 返回严格大于给定键的最小键;如果不存在这样的键,则返回 null。K higherKey(K key)// 如果此映射未包含键-值映射关系,则返回 true。boolean isEmpty()// 返回此映射中所包含键的 NavigableSet 视图。NavigableSet<K> keySet()// 返回与此映射中的最大键关联的键-值映射关系;如果该映射为空,则返回 null。Map.Entry<K,V> lastEntry()// 返回映射中当前最后一个(最高)键。K lastKey()// 返回与严格小于给定键的最大键关联的键-值映射关系;如果不存在这样的键,则返回 null。Map.Entry<K,V> lowerEntry(K key)// 返回严格小于给定键的最大键;如果不存在这样的键,则返回 null。K lowerKey(K key)// 返回此映射中所包含键的 NavigableSet 视图。NavigableSet<K> navigableKeySet()// 移除并返回与此映射中的最小键关联的键-值映射关系;如果该映射为空,则返回 null。Map.Entry<K,V> pollFirstEntry()// 移除并返回与此映射中的最大键关联的键-值映射关系;如果该映射为空,则返回 null。Map.Entry<K,V> pollLastEntry()// 将指定值与此映射中的指定键关联。V put(K key, V value)// 如果指定键已经不再与某个值相关联,则将它与给定值关联。V putIfAbsent(K key, V value)// 从此映射中移除指定键的映射关系(如果存在)。V remove(Object key)// 只有目前将键的条目映射到给定值时,才移除该键的条目。boolean remove(Object key, Object value)// 只有目前将键的条目映射到某一值时,才替换该键的条目。V replace(K key, V value)// 只有目前将键的条目映射到给定值时,才替换该键的条目。boolean replace(K key, V oldValue, V newValue)// 返回此映射中的键-值映射关系数。int size()// 返回此映射的部分视图,其键的范围从 fromKey 到 toKey。ConcurrentNavigableMap<K,V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive)// 返回此映射的部分视图,其键值的范围从 fromKey(包括)到 toKey(不包括)。ConcurrentNavigableMap<K,V> subMap(K fromKey, K toKey)// 返回此映射的部分视图,其键大于等于 fromKey。ConcurrentNavigableMap<K,V> tailMap(K fromKey)// 返回此映射的部分视图,其键大于(或等于,如果 inclusive 为 true)fromKey。ConcurrentNavigableMap<K,V> tailMap(K fromKey, boolean inclusive)// 返回此映射中所包含值的 Collection 视图。Collection<V> values()
ConcurrentSkipListMap源码分析(JDK1.7.0_40版本)
ConcurrentSkipListMap.java的完整源码如下:
1 /* 2 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * 11 * 12 * 13 * 14 * 15 * 16 * 17 * 18 * 19 * 20 * 21 * 22 * 23 */ 24 25 /* 26 * 27 * 28 * 29 * 30 * 31 * Written by Doug Lea with assistance from members of JCP JSR-166 32 * Expert Group and released to the public domain, as explained at 33 * http://creativecommons.org/publicdomain/zero/1.0/ 34 */ 35 36 package java.util.concurrent; 37 import java.util.*; 38 import java.util.concurrent.atomic.*; 39 40 /** 41 * A scalable concurrent {@link ConcurrentNavigableMap} implementation. 42 * The map is sorted according to the {@linkplain Comparable natural 43 * ordering} of its keys, or by a {@link Comparator} provided at map 44 * creation time, depending on which constructor is used. 45 * 46 * <p>This class implements a concurrent variant of <a 47 * href="http://en.wikipedia.org/wiki/Skip_list" target="_top">SkipLists</a> 48 * providing expected average <i>log(n)</i> time cost for the 49 * <tt>containsKey</tt>, <tt>get</tt>, <tt>put</tt> and 50 * <tt>remove</tt> operations and their variants. Insertion, removal, 51 * update, and access operations safely execute concurrently by 52 * multiple threads. Iterators are <i>weakly consistent</i>, returning 53 * elements reflecting the state of the map at some point at or since 54 * the creation of the iterator. They do <em>not</em> throw {@link 55 * ConcurrentModificationException}, and may proceed concurrently with 56 * other operations. Ascending key ordered views and their iterators 57 * are faster than descending ones. 58 * 59 * <p>All <tt>Map.Entry</tt> pairs returned by methods in this class 60 * and its views represent snapshots of mappings at the time they were 61 * produced. They do <em>not</em> support the <tt>Entry.setValue</tt> 62 * method. (Note however that it is possible to change mappings in the 63 * associated map using <tt>put</tt>, <tt>putIfAbsent</tt>, or 64 * <tt>replace</tt>, depending on exactly which effect you need.) 65 * 66 * <p>Beware that, unlike in most collections, the <tt>size</tt> 67 * method is <em>not</em> a constant-time operation. Because of the 68 * asynchronous nature of these maps, determining the current number 69 * of elements requires a traversal of the elements, and so may report 70 * inaccurate results if this collection is modified during traversal. 71 * Additionally, the bulk operations <tt>putAll</tt>, <tt>equals</tt>, 72 * <tt>toArray</tt>, <tt>containsValue</tt>, and <tt>clear</tt> are 73 * <em>not</em> guaranteed to be performed atomically. For example, an 74 * iterator operating concurrently with a <tt>putAll</tt> operation 75 * might view only some of the added elements. 76 * 77 * <p>This class and its views and iterators implement all of the 78 * <em>optional</em> methods of the {@link Map} and {@link Iterator} 79 * interfaces. Like most other concurrent collections, this class does 80 * <em>not</em> permit the use of <tt>null</tt> keys or values because some 81 * null return values cannot be reliably distinguished from the absence of 82 * elements. 83 * 84 * <p>This class is a member of the 85 * <a href="{@docRoot}/../technotes/guides/collections/index.html"> 86 * Java Collections Framework</a>. 87 * 88 * @author Doug Lea 89 * @param <K> the type of keys maintained by this map 90 * @param <V> the type of mapped values 91 * @since 1.6 92 */ 93 public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V> 94 implements ConcurrentNavigableMap<K,V>, 95 Cloneable, 96 java.io.Serializable { 97 /* 98 * This class implements a tree-like two-dimensionally linked skip 99 * list in which the index levels are represented in separate 100 * nodes from the base nodes holding data. There are two reasons 101 * for taking this approach instead of the usual array-based 102 * structure: 1) Array based implementations seem to encounter 103 * more complexity and overhead 2) We can use cheaper algorithms 104 * for the heavily-traversed index lists than can be used for the 105 * base lists. Here's a picture of some of the basics for a 106 * possible list with 2 levels of index: 107 * 108 * Head nodes Index nodes 109 * +-+ right +-+ +-+ 110 * |2|---------------->| |--------------------->| |->null 111 * +-+ +-+ +-+ 112 * | down | | 113 * v v v 114 * +-+ +-+ +-+ +-+ +-+ +-+ 115 * |1|----------->| |->| |------>| |----------->| |------>| |->null 116 * +-+ +-+ +-+ +-+ +-+ +-+ 117 * v | | | | | 118 * Nodes next v v v v v 119 * +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ 120 * | |->|A|->|B|->|C|->|D|->|E|->|F|->|G|->|H|->|I|->|J|->|K|->null 121 * +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ 122 * 123 * The base lists use a variant of the HM linked ordered set 124 * algorithm. See Tim Harris, "A pragmatic implementation of 125 * non-blocking linked lists" 126 * http://www.cl.cam.ac.uk/~tlh20/publications.html and Maged 127 * Michael "High Performance Dynamic Lock-Free Hash Tables and 128 * List-Based Sets" 129 * http://www.research.ibm.com/people/m/michael/pubs.htm. The 130 * basic idea in these lists is to mark the "next" pointers of 131 * deleted nodes when deleting to avoid conflicts with concurrent 132 * insertions, and when traversing to keep track of triples 133 * (predecessor, node, successor) in order to detect when and how 134 * to unlink these deleted nodes. 135 * 136 * Rather than using mark-bits to mark list deletions (which can 137 * be slow and space-intensive using AtomicMarkedReference), nodes 138 * use direct CAS'able next pointers. On deletion, instead of 139 * marking a pointer, they splice in another node that can be 140 * thought of as standing for a marked pointer (indicating this by 141 * using otherwise impossible field values). Using plain nodes 142 * acts roughly like "boxed" implementations of marked pointers, 143 * but uses new nodes only when nodes are deleted, not for every 144 * link. This requires less space and supports faster 145 * traversal. Even if marked references were better supported by 146 * JVMs, traversal using this technique might still be faster 147 * because any search need only read ahead one more node than 148 * otherwise required (to check for trailing marker) rather than 149 * unmasking mark bits or whatever on each read. 150 * 151 * This approach maintains the essential property needed in the HM 152 * algorithm of changing the next-pointer of a deleted node so 153 * that any other CAS of it will fail, but implements the idea by 154 * changing the pointer to point to a different node, not by 155 * marking it. While it would be possible to further squeeze 156 * space by defining marker nodes not to have key/value fields, it 157 * isn't worth the extra type-testing overhead. The deletion 158 * markers are rarely encountered during traversal and are 159 * normally quickly garbage collected. (Note that this technique 160 * would not work well in systems without garbage collection.) 161 * 162 * In addition to using deletion markers, the lists also use 163 * nullness of value fields to indicate deletion, in a style 164 * similar to typical lazy-deletion schemes. If a node's value is 165 * null, then it is considered logically deleted and ignored even 166 * though it is still reachable. This maintains proper control of 167 * concurrent replace vs delete operations -- an attempted replace 168 * must fail if a delete beat it by nulling field, and a delete 169 * must return the last non-null value held in the field. (Note: 170 * Null, rather than some special marker, is used for value fields 171 * here because it just so happens to mesh with the Map API 172 * requirement that method get returns null if there is no 173 * mapping, which allows nodes to remain concurrently readable 174 * even when deleted. Using any other marker value here would be 175 * messy at best.) 176 * 177 * Here's the sequence of events for a deletion of node n with 178 * predecessor b and successor f, initially: 179 * 180 * +------+ +------+ +------+ 181 * ... | b |------>| n |----->| f | ... 182 * +------+ +------+ +------+ 183 * 184 * 1. CAS n's value field from non-null to null. 185 * From this point on, no public operations encountering 186 * the node consider this mapping to exist. However, other 187 * ongoing insertions and deletions might still modify 188 * n's next pointer. 189 * 190 * 2. CAS n's next pointer to point to a new marker node. 191 * From this point on, no other nodes can be appended to n. 192 * which avoids deletion errors in CAS-based linked lists. 193 * 194 * +------+ +------+ +------+ +------+ 195 * ... | b |------>| n |----->|marker|------>| f | ... 196 * +------+ +------+ +------+ +------+ 197 * 198 * 3. CAS b's next pointer over both n and its marker. 199 * From this point on, no new traversals will encounter n, 200 * and it can eventually be GCed. 201 * +------+ +------+ 202 * ... | b |----------------------------------->| f | ... 203 * +------+ +------+ 204 * 205 * A failure at step 1 leads to simple retry due to a lost race 206 * with another operation. Steps 2-3 can fail because some other 207 * thread noticed during a traversal a node with null value and 208 * helped out by marking and/or unlinking. This helping-out 209 * ensures that no thread can become stuck waiting for progress of 210 * the deleting thread. The use of marker nodes slightly 211 * complicates helping-out code because traversals must track 212 * consistent reads of up to four nodes (b, n, marker, f), not 213 * just (b, n, f), although the next field of a marker is 214 * immutable, and once a next field is CAS'ed to point to a 215 * marker, it never again changes, so this requires less care. 216 * 217 * Skip lists add indexing to this scheme, so that the base-level 218 * traversals start close to the locations being found, inserted 219 * or deleted -- usually base level traversals only traverse a few 220 * nodes. This doesn't change the basic algorithm except for the 221 * need to make sure base traversals start at predecessors (here, 222 * b) that are not (structurally) deleted, otherwise retrying 223 * after processing the deletion. 224 * 225 * Index levels are maintained as lists with volatile next fields, 226 * using CAS to link and unlink. Races are allowed in index-list 227 * operations that can (rarely) fail to link in a new index node 228 * or delete one. (We can't do this of course for data nodes.) 229 * However, even when this happens, the index lists remain sorted, 230 * so correctly serve as indices. This can impact performance, 231 * but since skip lists are probabilistic anyway, the net result 232 * is that under contention, the effective "p" value may be lower 233 * than its nominal value. And race windows are kept small enough 234 * that in practice these failures are rare, even under a lot of 235 * contention. 236 * 237 * The fact that retries (for both base and index lists) are 238 * relatively cheap due to indexing allows some minor 239 * simplifications of retry logic. Traversal restarts are 240 * performed after most "helping-out" CASes. This isn't always 241 * strictly necessary, but the implicit backoffs tend to help 242 * reduce other downstream failed CAS's enough to outweigh restart 243 * cost. This worsens the worst case, but seems to improve even 244 * highly contended cases. 245 * 246 * Unlike most skip-list implementations, index insertion and 247 * deletion here require a separate traversal pass occuring after 248 * the base-level action, to add or remove index nodes. This adds 249 * to single-threaded overhead, but improves contended 250 * multithreaded performance by narrowing interference windows, 251 * and allows deletion to ensure that all index nodes will be made 252 * unreachable upon return from a public remove operation, thus 253 * avoiding unwanted garbage retention. This is more important 254 * here than in some other data structures because we cannot null 255 * out node fields referencing user keys since they might still be 256 * read by other ongoing traversals. 257 * 258 * Indexing uses skip list parameters that maintain good search 259 * performance while using sparser-than-usual indices: The 260 * hardwired parameters k=1, p=0.5 (see method randomLevel) mean 261 * that about one-quarter of the nodes have indices. Of those that 262 * do, half have one level, a quarter have two, and so on (see 263 * Pugh's Skip List Cookbook, sec 3.4). The expected total space 264 * requirement for a map is slightly less than for the current 265 * implementation of java.util.TreeMap. 266 * 267 * Changing the level of the index (i.e, the height of the 268 * tree-like structure) also uses CAS. The head index has initial 269 * level/height of one. Creation of an index with height greater 270 * than the current level adds a level to the head index by 271 * CAS'ing on a new top-most head. To maintain good performance 272 * after a lot of removals, deletion methods heuristically try to 273 * reduce the height if the topmost levels appear to be empty. 274 * This may encounter races in which it possible (but rare) to 275 * reduce and "lose" a level just as it is about to contain an 276 * index (that will then never be encountered). This does no 277 * structural harm, and in practice appears to be a better option 278 * than allowing unrestrained growth of levels. 279 * 280 * The code for all this is more verbose than you'd like. Most 281 * operations entail locating an element (or position to insert an 282 * element). The code to do this can't be nicely factored out 283 * because subsequent uses require a snapshot of predecessor 284 * and/or successor and/or value fields which can't be returned 285 * all at once, at least not without creating yet another object 286 * to hold them -- creating such little objects is an especially 287 * bad idea for basic internal search operations because it adds 288 * to GC overhead. (This is one of the few times I've wished Java 289 * had macros.) Instead, some traversal code is interleaved within 290 * insertion and removal operations. The control logic to handle 291 * all the retry conditions is sometimes twisty. Most search is 292 * broken into 2 parts. findPredecessor() searches index nodes 293 * only, returning a base-level predecessor of the key. findNode() 294 * finishes out the base-level search. Even with this factoring, 295 * there is a fair amount of near-duplication of code to handle 296 * variants. 297 * 298 * For explanation of algorithms sharing at least a couple of 299 * features with this one, see Mikhail Fomitchev's thesis 300 * (http://www.cs.yorku.ca/~mikhail/), Keir Fraser's thesis 301 * (http://www.cl.cam.ac.uk/users/kaf24/), and Hakan Sundell's 302 * thesis (http://www.cs.chalmers.se/~phs/). 303 * 304 * Given the use of tree-like index nodes, you might wonder why 305 * this doesn't use some kind of search tree instead, which would 306 * support somewhat faster search operations. The reason is that 307 * there are no known efficient lock-free insertion and deletion 308 * algorithms for search trees. The immutability of the "down" 309 * links of index nodes (as opposed to mutable "left" fields in 310 * true trees) makes this tractable using only CAS operations. 311 * 312 * Notation guide for local variables 313 * Node: b, n, f for predecessor, node, successor 314 * Index: q, r, d for index node, right, down. 315 * t for another index node 316 * Head: h 317 * Levels: j 318 * Keys: k, key 319 * Values: v, value 320 * Comparisons: c 321 */ 322 323 private static final long serialVersionUID = -8627078645895051609L; 324 325 /** 326 * Generates the initial random seed for the cheaper per-instance 327 * random number generators used in randomLevel. 328 */ 329 private static final Random seedGenerator = new Random(); 330 331 /** 332 * Special value used to identify base-level header 333 */ 334 private static final Object BASE_HEADER = new Object(); 335 336 /** 337 * The topmost head index of the skiplist. 338 */ 339 private transient volatile HeadIndex<K,V> head; 340 341 /** 342 * The comparator used to maintain order in this map, or null 343 * if using natural ordering. 344 * @serial 345 */ 346 private final Comparator<? super K> comparator; 347 348 /** 349 * Seed for simple random number generator. Not volatile since it 350 * doesn't matter too much if different threads don't see updates. 351 */ 352 private transient int randomSeed; 353 354 /** Lazily initialized key set */ 355 private transient KeySet keySet; 356 /** Lazily initialized entry set */ 357 private transient EntrySet entrySet; 358 /** Lazily initialized values collection */ 359 private transient Values values; 360 /** Lazily initialized descending key set */ 361 private transient ConcurrentNavigableMap<K,V> descendingMap; 362 363 /** 364 * Initializes or resets state. Needed by constructors, clone, 365 * clear, readObject. and ConcurrentSkipListSet.clone. 366 * (Note that comparator must be separately initialized.) 367 */ 368 final void initialize() { 369 keySet = null; 370 entrySet = null; 371 values = null; 372 descendingMap = null; 373 randomSeed = seedGenerator.nextInt() | 0x0100; // ensure nonzero 374 head = new HeadIndex<K,V>(new Node<K,V>(null, BASE_HEADER, null), 375 null, null, 1); 376 } 377 378 /** 379 * compareAndSet head node 380 */ 381 private boolean casHead(HeadIndex<K,V> cmp, HeadIndex<K,V> val) { 382 return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val); 383 } 384 385 /* ---------------- Nodes -------------- */ 386 387 /** 388 * Nodes hold keys and values, and are singly linked in sorted 389 * order, possibly with some intervening marker nodes. The list is 390 * headed by a dummy node accessible as head.node. The value field 391 * is declared only as Object because it takes special non-V 392 * values for marker and header nodes. 393 */ 394 static final class Node<K,V> { 395 final K key; 396 volatile Object value; 397 volatile Node<K,V> next; 398 399 /** 400 * Creates a new regular node. 401 */ 402 Node(K key, Object value, Node<K,V> next) { 403 this.key = key; 404 this.value = value; 405 this.next = next; 406 } 407 408 /** 409 * Creates a new marker node. A marker is distinguished by 410 * having its value field point to itself. Marker nodes also 411 * have null keys, a fact that is exploited in a few places, 412 * but this doesn't distinguish markers from the base-level 413 * header node (head.node), which also has a null key. 414 */ 415 Node(Node<K,V> next) { 416 this.key = null; 417 this.value = this; 418 this.next = next; 419 } 420 421 /** 422 * compareAndSet value field 423 */ 424 boolean casValue(Object cmp, Object val) { 425 return UNSAFE.compareAndSwapObject(this, valueOffset, cmp, val); 426 } 427 428 /** 429 * compareAndSet next field 430 */ 431 boolean casNext(Node<K,V> cmp, Node<K,V> val) { 432 return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val); 433 } 434 435 /** 436 * Returns true if this node is a marker. This method isn't 437 * actually called in any current code checking for markers 438 * because callers will have already read value field and need 439 * to use that read (not another done here) and so directly 440 * test if value points to node. 441 * @param n a possibly null reference to a node 442 * @return true if this node is a marker node 443 */ 444 boolean isMarker() { 445 return value == this; 446 } 447 448 /** 449 * Returns true if this node is the header of base-level list. 450 * @return true if this node is header node 451 */ 452 boolean isBaseHeader() { 453 return value == BASE_HEADER; 454 } 455 456 /** 457 * Tries to append a deletion marker to this node. 458 * @param f the assumed current successor of this node 459 * @return true if successful 460 */ 461 boolean appendMarker(Node<K,V> f) { 462 return casNext(f, new Node<K,V>(f)); 463 } 464 465 /** 466 * Helps out a deletion by appending marker or unlinking from 467 * predecessor. This is called during traversals when value 468 * field seen to be null. 469 * @param b predecessor 470 * @param f successor 471 */ 472 void helpDelete(Node<K,V> b, Node<K,V> f) { 473 /* 474 * Rechecking links and then doing only one of the 475 * help-out stages per call tends to minimize CAS 476 * interference among helping threads. 477 */ 478 if (f == next && this == b.next) { 479 if (f == null || f.value != f) // not already marked 480 appendMarker(f); 481 else 482 b.casNext(this, f.next); 483 } 484 } 485 486 /** 487 * Returns value if this node contains a valid key-value pair, 488 * else null. 489 * @return this node's value if it isn't a marker or header or 490 * is deleted, else null. 491 */ 492 V getValidValue() { 493 Object v = value; 494 if (v == this || v == BASE_HEADER) 495 return null; 496 return (V)v; 497 } 498 499 /** 500 * Creates and returns a new SimpleImmutableEntry holding current 501 * mapping if this node holds a valid value, else null. 502 * @return new entry or null 503 */ 504 AbstractMap.SimpleImmutableEntry<K,V> createSnapshot() { 505 V v = getValidValue(); 506 if (v == null) 507 return null; 508 return new AbstractMap.SimpleImmutableEntry<K,V>(key, v); 509 } 510 511 // UNSAFE mechanics 512 513 private static final sun.misc.Unsafe UNSAFE; 514 private static final long valueOffset; 515 private static final long nextOffset; 516 517 static { 518 try { 519 UNSAFE = sun.misc.Unsafe.getUnsafe(); 520 Class k = Node.class; 521 valueOffset = UNSAFE.objectFieldOffset 522 (k.getDeclaredField("value")); 523 nextOffset = UNSAFE.objectFieldOffset 524 (k.getDeclaredField("next")); 525 } catch (Exception e) { 526 throw new Error(e); 527 } 528 } 529 } 530 531 /* ---------------- Indexing -------------- */ 532 533 /** 534 * Index nodes represent the levels of the skip list. Note that 535 * even though both Nodes and Indexes have forward-pointing 536 * fields, they have different types and are handled in different 537 * ways, that can't nicely be captured by placing field in a 538 * shared abstract class. 539 */ 540 static class Index<K,V> { 541 final Node<K,V> node; 542 final Index<K,V> down; 543 volatile Index<K,V> right; 544 545 /** 546 * Creates index node with given values. 547 */ 548 Index(Node<K,V> node, Index<K,V> down, Index<K,V> right) { 549 this.node = node; 550 this.down = down; 551 this.right = right; 552 } 553 554 /** 555 * compareAndSet right field 556 */ 557 final boolean casRight(Index<K,V> cmp, Index<K,V> val) { 558 return UNSAFE.compareAndSwapObject(this, rightOffset, cmp, val); 559 } 560 561 /** 562 * Returns true if the node this indexes has been deleted. 563 * @return true if indexed node is known to be deleted 564 */ 565 final boolean indexesDeletedNode() { 566 return node.value == null; 567 } 568 569 /** 570 * Tries to CAS newSucc as successor. To minimize races with 571 * unlink that may lose this index node, if the node being 572 * indexed is known to be deleted, it doesn't try to link in. 573 * @param succ the expected current successor 574 * @param newSucc the new successor 575 * @return true if successful 576 */ 577 final boolean link(Index<K,V> succ, Index<K,V> newSucc) { 578 Node<K,V> n = node; 579 newSucc.right = succ; 580 return n.value != null && casRight(succ, newSucc); 581 } 582 583 /** 584 * Tries to CAS right field to skip over apparent successor 585 * succ. Fails (forcing a retraversal by caller) if this node 586 * is known to be deleted. 587 * @param succ the expected current successor 588 * @return true if successful 589 */ 590 final boolean unlink(Index<K,V> succ) { 591 return !indexesDeletedNode() && casRight(succ, succ.right); 592 } 593 594 // Unsafe mechanics 595 private static final sun.misc.Unsafe UNSAFE; 596 private static final long rightOffset; 597 static { 598 try { 599 UNSAFE = sun.misc.Unsafe.getUnsafe(); 600 Class k = Index.class; 601 rightOffset = UNSAFE.objectFieldOffset 602 (k.getDeclaredField("right")); 603 } catch (Exception e) { 604 throw new Error(e); 605 } 606 } 607 } 608 609 /* ---------------- Head nodes -------------- */ 610 611 /** 612 * Nodes heading each level keep track of their level. 613 */ 614 static final class HeadIndex<K,V> extends Index<K,V> { 615 final int level; 616 HeadIndex(Node<K,V> node, Index<K,V> down, Index<K,V> right, int level) { 617 super(node, down, right); 618 this.level = level; 619 } 620 } 621 622 /* ---------------- Comparison utilities -------------- */ 623 624 /** 625 * Represents a key with a comparator as a Comparable. 626 * 627 * Because most sorted collections seem to use natural ordering on 628 * Comparables (Strings, Integers, etc), most internal methods are 629 * geared to use them. This is generally faster than checking 630 * per-comparison whether to use comparator or comparable because 631 * it doesn't require a (Comparable) cast for each comparison. 632 * (Optimizers can only sometimes remove such redundant checks 633 * themselves.) When Comparators are used, 634 * ComparableUsingComparators are created so that they act in the 635 * same way as natural orderings. This penalizes use of 636 * Comparators vs Comparables, which seems like the right 637 * tradeoff. 638 */ 639 static final class ComparableUsingComparator<K> implements Comparable<K> { 640 final K actualKey; 641 final Comparator<? super K> cmp; 642 ComparableUsingComparator(K key, Comparator<? super K> cmp) { 643 this.actualKey = key; 644 this.cmp = cmp; 645 } 646 public int compareTo(K k2) { 647 return cmp.compare(actualKey, k2); 648 } 649 } 650 651 /** 652 * If using comparator, return a ComparableUsingComparator, else 653 * cast key as Comparable, which may cause ClassCastException, 654 * which is propagated back to caller. 655 */ 656 private Comparable<? super K> comparable(Object key) 657 throws ClassCastException { 658 if (key == null) 659 throw new NullPointerException(); 660 if (comparator != null) 661 return new ComparableUsingComparator<K>((K)key, comparator); 662 else 663 return (Comparable<? super K>)key; 664 } 665 666 /** 667 * Compares using comparator or natural ordering. Used when the 668 * ComparableUsingComparator approach doesn't apply. 669 */ 670 int compare(K k1, K k2) throws ClassCastException { 671 Comparator<? super K> cmp = comparator; 672 if (cmp != null) 673 return cmp.compare(k1, k2); 674 else 675 return ((Comparable<? super K>)k1).compareTo(k2); 676 } 677 678 /** 679 * Returns true if given key greater than or equal to least and 680 * strictly less than fence, bypassing either test if least or 681 * fence are null. Needed mainly in submap operations. 682 */ 683 boolean inHalfOpenRange(K key, K least, K fence) { 684 if (key == null) 685 throw new NullPointerException(); 686 return ((least == null || compare(key, least) >= 0) && 687 (fence == null || compare(key, fence) < 0)); 688 } 689 690 /** 691 * Returns true if given key greater than or equal to least and less 692 * or equal to fence. Needed mainly in submap operations. 693 */ 694 boolean inOpenRange(K key, K least, K fence) { 695 if (key == null) 696 throw new NullPointerException(); 697 return ((least == null || compare(key, least) >= 0) && 698 (fence == null || compare(key, fence) <= 0)); 699 } 700 701 /* ---------------- Traversal -------------- */ 702 703 /** 704 * Returns a base-level node with key strictly less than given key, 705 * or the base-level header if there is no such node. Also 706 * unlinks indexes to deleted nodes found along the way. Callers 707 * rely on this side-effect of clearing indices to deleted nodes. 708 * @param key the key 709 * @return a predecessor of key 710 */ 711 private Node<K,V> findPredecessor(Comparable<? super K> key) { 712 if (key == null) 713 throw new NullPointerException(); // don't postpone errors 714 for (;;) { 715 Index<K,V> q = head; 716 Index<K,V> r = q.right; 717 for (;;) { 718 if (r != null) { 719 Node<K,V> n = r.node; 720 K k = n.key; 721 if (n.value == null) { 722 if (!q.unlink(r)) 723 break; // restart 724 r = q.right; // reread r 725 continue; 726 } 727 if (key.compareTo(k) > 0) { 728 q = r; 729 r = r.right; 730 continue; 731 } 732 } 733 Index<K,V> d = q.down; 734 if (d != null) { 735 q = d; 736 r = d.right; 737 } else 738 return q.node; 739 } 740 } 741 } 742 743 /** 744 * Returns node holding key or null if no such, clearing out any 745 * deleted nodes seen along the way. Repeatedly traverses at 746 * base-level looking for key starting at predecessor returned 747 * from findPredecessor, processing base-level deletions as 748 * encountered. Some callers rely on this side-effect of clearing 749 * deleted nodes. 750 * 751 * Restarts occur, at traversal step centered on node n, if: 752 * 753 * (1) After reading n's next field, n is no longer assumed 754 * predecessor b's current successor, which means that 755 * we don't have a consistent 3-node snapshot and so cannot 756 * unlink any subsequent deleted nodes encountered. 757 * 758 * (2) n's value field is null, indicating n is deleted, in 759 * which case we help out an ongoing structural deletion 760 * before retrying. Even though there are cases where such 761 * unlinking doesn't require restart, they aren't sorted out 762 * here because doing so would not usually outweigh cost of 763 * restarting. 764 * 765 * (3) n is a marker or n's predecessor's value field is null, 766 * indicating (among other possibilities) that 767 * findPredecessor returned a deleted node. We can't unlink 768 * the node because we don't know its predecessor, so rely 769 * on another call to findPredecessor to notice and return 770 * some earlier predecessor, which it will do. This check is 771 * only strictly needed at beginning of loop, (and the 772 * b.value check isn't strictly needed at all) but is done 773 * each iteration to help avoid contention with other 774 * threads by callers that will fail to be able to change 775 * links, and so will retry anyway. 776 * 777 * The traversal loops in doPut, doRemove, and findNear all 778 * include the same three kinds of checks. And specialized 779 * versions appear in findFirst, and findLast and their 780 * variants. They can't easily share code because each uses the 781 * reads of fields held in locals occurring in the orders they 782 * were performed. 783 * 784 * @param key the key 785 * @return node holding key, or null if no such 786 */ 787 private Node<K,V> findNode(Comparable<? super K> key) { 788 for (;;) { 789 Node<K,V> b = findPredecessor(key); 790 Node<K,V> n = b.next; 791 for (;;) { 792 if (n == null) 793 return null; 794 Node<K,V> f = n.next; 795 if (n != b.next) // inconsistent read 796 break; 797 Object v = n.value; 798 if (v == null) { // n is deleted 799 n.helpDelete(b, f); 800 break; 801 } 802 if (v == n || b.value == null) // b is deleted 803 break; 804 int c = key.compareTo(n.key); 805 if (c == 0) 806 return n; 807 if (c < 0) 808 return null; 809 b = n; 810 n = f; 811 } 812 } 813 } 814 815 /** 816 * Gets value for key using findNode. 817 * @param okey the key 818 * @return the value, or null if absent 819 */ 820 private V doGet(Object okey) { 821 Comparable<? super K> key = comparable(okey); 822 /* 823 * Loop needed here and elsewhere in case value field goes 824 * null just as it is about to be returned, in which case we 825 * lost a race with a deletion, so must retry. 826 */ 827 for (;;) { 828 Node<K,V> n = findNode(key); 829 if (n == null) 830 return null; 831 Object v = n.value; 832 if (v != null) 833 return (V)v; 834 } 835 } 836 837 /* ---------------- Insertion -------------- */ 838 839 /** 840 * Main insertion method. Adds element if not present, or 841 * replaces value if present and onlyIfAbsent is false. 842 * @param kkey the key 843 * @param value the value that must be associated with key 844 * @param onlyIfAbsent if should not insert if already present 845 * @return the old value, or null if newly inserted 846 */ 847 private V doPut(K kkey, V value, boolean onlyIfAbsent) { 848 Comparable<? super K> key = comparable(kkey); 849 for (;;) { 850 Node<K,V> b = findPredecessor(key); 851 Node<K,V> n = b.next; 852 for (;;) { 853 if (n != null) { 854 Node<K,V> f = n.next; 855 if (n != b.next) // inconsistent read 856 break; 857 Object v = n.value; 858 if (v == null) { // n is deleted 859 n.helpDelete(b, f); 860 break; 861 } 862 if (v == n || b.value == null) // b is deleted 863 break; 864 int c = key.compareTo(n.key); 865 if (c > 0) { 866 b = n; 867 n = f; 868 continue; 869 } 870 if (c == 0) { 871 if (onlyIfAbsent || n.casValue(v, value)) 872 return (V)v; 873 else 874 break; // restart if lost race to replace value 875 } 876 // else c < 0; fall through 877 } 878 879 Node<K,V> z = new Node<K,V>(kkey, value, n); 880 if (!b.casNext(n, z)) 881 break; // restart if lost race to append to b 882 int level = randomLevel(); 883 if (level > 0) 884 insertIndex(z, level); 885 return null; 886 } 887 } 888 } 889 890 /** 891 * Returns a random level for inserting a new node. 892 * Hardwired to k=1, p=0.5, max 31 (see above and 893 * Pugh's "Skip List Cookbook", sec 3.4). 894 * 895 * This uses the simplest of the generators described in George 896 * Marsaglia's "Xorshift RNGs" paper. This is not a high-quality 897 * generator but is acceptable here. 898 */ 899 private int randomLevel() { 900 int x = randomSeed; 901 x ^= x << 13; 902 x ^= x >>> 17; 903 randomSeed = x ^= x << 5; 904 if ((x & 0x80000001) != 0) // test highest and lowest bits 905 return 0; 906 int level = 1; 907 while (((x >>>= 1) & 1) != 0) ++level; 908 return level; 909 } 910 911 /** 912 * Creates and adds index nodes for the given node. 913 * @param z the node 914 * @param level the level of the index 915 */ 916 private void insertIndex(Node<K,V> z, int level) { 917 HeadIndex<K,V> h = head; 918 int max = h.level; 919 920 if (level <= max) { 921 Index<K,V> idx = null; 922 for (int i = 1; i <= level; ++i) 923 idx = new Index<K,V>(z, idx, null); 924 addIndex(idx, h, level); 925 926 } else { // Add a new level 927 /* 928 * To reduce interference by other threads checking for 929 * empty levels in tryReduceLevel, new levels are added 930 * with initialized right pointers. Which in turn requires 931 * keeping levels in an array to access them while 932 * creating new head index nodes from the opposite 933 * direction. 934 */ 935 level = max + 1; 936 Index<K,V>[] idxs = (Index<K,V>[])new Index[level+1]; 937 Index<K,V> idx = null; 938 for (int i = 1; i <= level; ++i) 939 idxs[i] = idx = new Index<K,V>(z, idx, null); 940 941 HeadIndex<K,V> oldh; 942 int k; 943 for (;;) { 944 oldh = head; 945 int oldLevel = oldh.level; 946 if (level <= oldLevel) { // lost race to add level 947 k = level; 948 break; 949 } 950 HeadIndex<K,V> newh = oldh; 951 Node<K,V> oldbase = oldh.node; 952 for (int j = oldLevel+1; j <= level; ++j) 953 newh = new HeadIndex<K,V>(oldbase, newh, idxs[j], j); 954 if (casHead(oldh, newh)) { 955 k = oldLevel; 956 break; 957 } 958 } 959 addIndex(idxs[k], oldh, k); 960 } 961 } 962 963 /** 964 * Adds given index nodes from given level down to 1. 965 * @param idx the topmost index node being inserted 966 * @param h the value of head to use to insert. This must be 967 * snapshotted by callers to provide correct insertion level 968 * @param indexLevel the level of the index 969 */ 970 private void addIndex(Index<K,V> idx, HeadIndex<K,V> h, int indexLevel) { 971 // Track next level to insert in case of retries 972 int insertionLevel = indexLevel; 973 Comparable<? super K> key = comparable(idx.node.key); 974 if (key == null) throw new NullPointerException(); 975 976 // Similar to findPredecessor, but adding index nodes along 977 // path to key. 978 for (;;) { 979 int j = h.level; 980 Index<K,V> q = h; 981 Index<K,V> r = q.right; 982 Index<K,V> t = idx; 983 for (;;) { 984 if (r != null) { 985 Node<K,V> n = r.node; 986 // compare before deletion check avoids needing recheck 987 int c = key.compareTo(n.key); 988 if (n.value == null) { 989 if (!q.unlink(r)) 990 break; 991 r = q.right; 992 continue; 993 } 994 if (c > 0) { 995 q = r; 996 r = r.right; 997 continue; 998 } 999 }1000 1001 if (j == insertionLevel) {1002 // Don't insert index if node already deleted1003 if (t.indexesDeletedNode()) {1004 findNode(key); // cleans up1005 return;1006 }1007 if (!q.link(r, t))1008 break; // restart1009 if (--insertionLevel == 0) {1010 // need final deletion check before return1011 if (t.indexesDeletedNode())1012 findNode(key);1013 return;1014 }1015 }1016 1017 if (--j >= insertionLevel && j < indexLevel)1018 t = t.down;1019 q = q.down;1020 r = q.right;1021 }1022 }1023 }1024 1025 /* ---------------- Deletion -------------- */1026 1027 /**1028 * Main deletion method. Locates node, nulls value, appends a1029 * deletion marker, unlinks predecessor, removes associated index1030 * nodes, and possibly reduces head index level.1031 *1032 * Index nodes are cleared out simply by calling findPredecessor.1033 * which unlinks indexes to deleted nodes found along path to key,1034 * which will include the indexes to this node. This is done1035 * unconditionally. We can't check beforehand whether there are1036 * index nodes because it might be the case that some or all1037 * indexes hadn't been inserted yet for this node during initial1038 * search for it, and we'd like to ensure lack of garbage1039 * retention, so must call to be sure.1040 *1041 * @param okey the key1042 * @param value if non-null, the value that must be1043 * associated with key1044 * @return the node, or null if not found1045 */1046 final V doRemove(Object okey, Object value) {1047 Comparable<? super K> key = comparable(okey);1048 for (;;) {1049 Node<K,V> b = findPredecessor(key);1050 Node<K,V> n = b.next;1051 for (;;) {1052 if (n == null)1053 return null;1054 Node<K,V> f = n.next;1055 if (n != b.next) // inconsistent read1056 break;1057 Object v = n.value;1058 if (v == null) { // n is deleted1059 n.helpDelete(b, f);1060 break;1061 }1062 if (v == n || b.value == null) // b is deleted1063 break;1064 int c = key.compareTo(n.key);1065 if (c < 0)1066 return null;1067 if (c > 0) {1068 b = n;1069 n = f;1070 continue;1071 }1072 if (value != null && !value.equals(v))1073 return null;1074 if (!n.casValue(v, null))1075 break;1076 if (!n.appendMarker(f) || !b.casNext(n, f))1077 findNode(key); // Retry via findNode1078 else {1079 findPredecessor(key); // Clean index1080 if (head.right == null)1081 tryReduceLevel();1082 }1083 return (V)v;1084 }1085 }1086 }1087 1088 /**1089 * Possibly reduce head level if it has no nodes. This method can1090 * (rarely) make mistakes, in which case levels can disappear even1091 * though they are about to contain index nodes. This impacts1092 * performance, not correctness. To minimize mistakes as well as1093 * to reduce hysteresis, the level is reduced by one only if the1094 * topmost three levels look empty. Also, if the removed level1095 * looks non-empty after CAS, we try to change it back quick1096 * before anyone notices our mistake! (This trick works pretty1097 * well because this method will practically never make mistakes1098 * unless current thread stalls immediately before first CAS, in1099 * which case it is very unlikely to stall again immediately1100 * afterwards, so will recover.)1101 *1102 * We put up with all this rather than just let levels grow1103 * because otherwise, even a small map that has undergone a large1104 * number of insertions and removals will have a lot of levels,1105 * slowing down access more than would an occasional unwanted1106 * reduction.1107 */1108 private void tryReduceLevel() {1109 HeadIndex<K,V> h = head;1110 HeadIndex<K,V> d;1111 HeadIndex<K,V> e;1112 if (h.level > 3 &&1113 (d = (HeadIndex<K,V>)h.down) != null &&1114 (e = (HeadIndex<K,V>)d.down) != null &&1115 e.right == null &&1116 d.right == null &&1117 h.right == null &&1118 casHead(h, d) && // try to set1119 h.right != null) // recheck1120 casHead(d, h); // try to backout1121 }1122 1123 /* ---------------- Finding and removing first element -------------- */1124 1125 /**1126 * Specialized variant of findNode to get first valid node.1127 * @return first node or null if empty1128 */1129 Node<K,V> findFirst() {1130 for (;;) {1131 Node<K,V> b = head.node;1132 Node<K,V> n = b.next;1133 if (n == null)1134 return null;1135 if (n.value != null)1136 return n;1137 n.helpDelete(b, n.next);1138 }1139 }1140 1141 /**1142 * Removes first entry; returns its snapshot.1143 * @return null if empty, else snapshot of first entry1144 */1145 Map.Entry<K,V> doRemoveFirstEntry() {1146 for (;;) {1147 Node<K,V> b = head.node;1148 Node<K,V> n = b.next;1149 if (n == null)1150 return null;1151 Node<K,V> f = n.next;1152 if (n != b.next)1153 continue;1154 Object v = n.value;1155 if (v == null) {1156 n.helpDelete(b, f);1157 continue;1158 }1159 if (!n.casValue(v, null))1160 continue;1161 if (!n.appendMarker(f) || !b.casNext(n, f))1162 findFirst(); // retry1163 clearIndexToFirst();1164 return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, (V)v);1165 }1166 }1167 1168 /**1169 * Clears out index nodes associated with deleted first entry.1170 */1171 private void clearIndexToFirst() {1172 for (;;) {1173 Index<K,V> q = head;1174 for (;;) {1175 Index<K,V> r = q.right;1176 if (r != null && r.indexesDeletedNode() && !q.unlink(r))1177 break;1178 if ((q = q.down) == null) {1179 if (head.right == null)1180 tryReduceLevel();1181 return;1182 }1183 }1184 }1185 }1186 1187 1188 /* ---------------- Finding and removing last element -------------- */1189 1190 /**1191 * Specialized version of find to get last valid node.1192 * @return last node or null if empty1193 */1194 Node<K,V> findLast() {1195 /*1196 * findPredecessor can't be used to traverse index level1197 * because this doesn't use comparisons. So traversals of1198 * both levels are folded together.1199 */1200 Index<K,V> q = head;1201 for (;;) {1202 Index<K,V> d, r;1203 if ((r = q.right) != null) {1204 if (r.indexesDeletedNode()) {1205 q.unlink(r);1206 q = head; // restart1207 }1208 else1209 q = r;1210 } else if ((d = q.down) != null) {1211 q = d;1212 } else {1213 Node<K,V> b = q.node;1214 Node<K,V> n = b.next;1215 for (;;) {1216 if (n == null)1217 return b.isBaseHeader() ? null : b;1218 Node<K,V> f = n.next; // inconsistent read1219 if (n != b.next)1220 break;1221 Object v = n.value;1222 if (v == null) { // n is deleted1223 n.helpDelete(b, f);1224 break;1225 }1226 if (v == n || b.value == null) // b is deleted1227 break;1228 b = n;1229 n = f;1230 }1231 q = head; // restart1232 }1233 }1234 }1235 1236 /**1237 * Specialized variant of findPredecessor to get predecessor of last1238 * valid node. Needed when removing the last entry. It is possible1239 * that all successors of returned node will have been deleted upon1240 * return, in which case this method can be retried.1241 * @return likely predecessor of last node1242 */1243 private Node<K,V> findPredecessorOfLast() {1244 for (;;) {1245 Index<K,V> q = head;1246 for (;;) {1247 Index<K,V> d, r;1248 if ((r = q.right) != null) {1249 if (r.indexesDeletedNode()) {1250 q.unlink(r);1251 break; // must restart1252 }1253 // proceed as far across as possible without overshooting1254 if (r.node.next != null) {1255 q = r;1256 continue;1257 }1258 }1259 if ((d = q.down) != null)1260 q = d;1261 else1262 return q.node;1263 }1264 }1265 }1266 1267 /**1268 * Removes last entry; returns its snapshot.1269 * Specialized variant of doRemove.1270 * @return null if empty, else snapshot of last entry1271 */1272 Map.Entry<K,V> doRemoveLastEntry() {1273 for (;;) {1274 Node<K,V> b = findPredecessorOfLast();1275 Node<K,V> n = b.next;1276 if (n == null) {1277 if (b.isBaseHeader()) // empty1278 return null;1279 else1280 continue; // all b's successors are deleted; retry1281 }1282 for (;;) {1283 Node<K,V> f = n.next;1284 if (n != b.next) // inconsistent read1285 break;1286 Object v = n.value;1287 if (v == null) { // n is deleted1288 n.helpDelete(b, f);1289 break;1290 }1291 if (v == n || b.value == null) // b is deleted1292 break;1293 if (f != null) {1294 b = n;1295 n = f;1296 continue;1297 }1298 if (!n.casValue(v, null))1299 break;1300 K key = n.key;1301 Comparable<? super K> ck = comparable(key);1302 if (!n.appendMarker(f) || !b.casNext(n, f))1303 findNode(ck); // Retry via findNode1304 else {1305 findPredecessor(ck); // Clean index1306 if (head.right == null)1307 tryReduceLevel();1308 }1309 return new AbstractMap.SimpleImmutableEntry<K,V>(key, (V)v);1310 }1311 }1312 }1313 1314 /* ---------------- Relational operations -------------- */1315 1316 // Control values OR'ed as arguments to findNear1317 1318 private static final int EQ = 1;1319 private static final int LT = 2;1320 private static final int GT = 0; // Actually checked as !LT1321 1322 /**1323 * Utility for ceiling, floor, lower, higher methods.1324 * @param kkey the key1325 * @param rel the relation -- OR'ed combination of EQ, LT, GT1326 * @return nearest node fitting relation, or null if no such1327 */1328 Node<K,V> findNear(K kkey, int rel) {1329 Comparable<? super K> key = comparable(kkey);1330 for (;;) {1331 Node<K,V> b = findPredecessor(key);1332 Node<K,V> n = b.next;1333 for (;;) {1334 if (n == null)1335 return ((rel & LT) == 0 || b.isBaseHeader()) ? null : b;1336 Node<K,V> f = n.next;1337 if (n != b.next) // inconsistent read1338 break;1339 Object v = n.value;1340 if (v == null) { // n is deleted1341 n.helpDelete(b, f);1342 break;1343 }1344 if (v == n || b.value == null) // b is deleted1345 break;1346 int c = key.compareTo(n.key);1347 if ((c == 0 && (rel & EQ) != 0) ||1348 (c < 0 && (rel & LT) == 0))1349 return n;1350 if ( c <= 0 && (rel & LT) != 0)1351 return b.isBaseHeader() ? null : b;1352 b = n;1353 n = f;1354 }1355 }1356 }1357 1358 /**1359 * Returns SimpleImmutableEntry for results of findNear.1360 * @param key the key1361 * @param rel the relation -- OR'ed combination of EQ, LT, GT1362 * @return Entry fitting relation, or null if no such1363 */1364 AbstractMap.SimpleImmutableEntry<K,V> getNear(K key, int rel) {1365 for (;;) {1366 Node<K,V> n = findNear(key, rel);1367 if (n == null)1368 return null;1369 AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();1370 if (e != null)1371 return e;1372 }1373 }1374 1375 1376 /* ---------------- Constructors -------------- */1377 1378 /**1379 * Constructs a new, empty map, sorted according to the1380 * {@linkplain Comparable natural ordering} of the keys.1381 */1382 public ConcurrentSkipListMap() {1383 this.comparator = null;1384 initialize();1385 }1386 1387 /**1388 * Constructs a new, empty map, sorted according to the specified1389 * comparator.1390 *1391 * @param comparator the comparator that will be used to order this map.1392 * If <tt>null</tt>, the {@linkplain Comparable natural1393 * ordering} of the keys will be used.1394 */1395 public ConcurrentSkipListMap(Comparator<? super K> comparator) {1396 this.comparator = comparator;1397 initialize();1398 }1399 1400 /**1401 * Constructs a new map containing the same mappings as the given map,1402 * sorted according to the {@linkplain Comparable natural ordering} of1403 * the keys.1404 *1405 * @param m the map whose mappings are to be placed in this map1406 * @throws ClassCastException if the keys in <tt>m</tt> are not1407 * {@link Comparable}, or are not mutually comparable1408 * @throws NullPointerException if the specified map or any of its keys1409 * or values are null1410 */1411 public ConcurrentSkipListMap(Map<? extends K, ? extends V> m) {1412 this.comparator = null;1413 initialize();1414 putAll(m);1415 }1416 1417 /**1418 * Constructs a new map containing the same mappings and using the1419 * same ordering as the specified sorted map.1420 *1421 * @param m the sorted map whose mappings are to be placed in this1422 * map, and whose comparator is to be used to sort this map1423 * @throws NullPointerException if the specified sorted map or any of1424 * its keys or values are null1425 */1426 public ConcurrentSkipListMap(SortedMap<K, ? extends V> m) {1427 this.comparator = m.comparator();1428 initialize();1429 buildFromSorted(m);1430 }1431 1432 /**1433 * Returns a shallow copy of this <tt>ConcurrentSkipListMap</tt>1434 * instance. (The keys and values themselves are not cloned.)1435 *1436 * @return a shallow copy of this map1437 */1438 public ConcurrentSkipListMap<K,V> clone() {1439 ConcurrentSkipListMap<K,V> clone = null;1440 try {1441 clone = (ConcurrentSkipListMap<K,V>) super.clone();1442 } catch (CloneNotSupportedException e) {1443 throw new InternalError();1444 }1445 1446 clone.initialize();1447 clone.buildFromSorted(this);1448 return clone;1449 }1450 1451 /**1452 * Streamlined bulk insertion to initialize from elements of1453 * given sorted map. Call only from constructor or clone1454 * method.1455 */1456 private void buildFromSorted(SortedMap<K, ? extends V> map) {1457 if (map == null)1458 throw new NullPointerException();1459 1460 HeadIndex<K,V> h = head;1461 Node<K,V> basepred = h.node;1462 1463 // Track the current rightmost node at each level. Uses an1464 // ArrayList to avoid committing to initial or maximum level.1465 ArrayList<Index<K,V>> preds = new ArrayList<Index<K,V>>();1466 1467 // initialize1468 for (int i = 0; i <= h.level; ++i)1469 preds.add(null);1470 Index<K,V> q = h;1471 for (int i = h.level; i > 0; --i) {1472 preds.set(i, q);1473 q = q.down;1474 }1475 1476 Iterator<? extends Map.Entry<? extends K, ? extends V>> it =1477 map.entrySet().iterator();1478 while (it.hasNext()) {1479 Map.Entry<? extends K, ? extends V> e = it.next();1480 int j = randomLevel();1481 if (j > h.level) j = h.level + 1;1482 K k = e.getKey();1483 V v = e.getValue();1484 if (k == null || v == null)1485 throw new NullPointerException();1486 Node<K,V> z = new Node<K,V>(k, v, null);1487 basepred.next = z;1488 basepred = z;1489 if (j > 0) {1490 Index<K,V> idx = null;1491 for (int i = 1; i <= j; ++i) {1492 idx = new Index<K,V>(z, idx, null);1493 if (i > h.level)1494 h = new HeadIndex<K,V>(h.node, h, idx, i);1495 1496 if (i < preds.size()) {1497 preds.get(i).right = idx;1498 preds.set(i, idx);1499 } else1500 preds.add(idx);1501 }1502 }1503 }1504 head = h;1505 }1506 1507 /* ---------------- Serialization -------------- */1508 1509 /**1510 * Save the state of this map to a stream.1511 *1512 * @serialData The key (Object) and value (Object) for each1513 * key-value mapping represented by the map, followed by1514 * <tt>null</tt>. The key-value mappings are emitted in key-order1515 * (as determined by the Comparator, or by the keys' natural1516 * ordering if no Comparator).1517 */1518 private void writeObject(java.io.ObjectOutputStream s)1519 throws java.io.IOException {1520 // Write out the Comparator and any hidden stuff1521 s.defaultWriteObject();1522 1523 // Write out keys and values (alternating)1524 for (Node<K,V> n = findFirst(); n != null; n = n.next) {1525 V v = n.getValidValue();1526 if (v != null) {1527 s.writeObject(n.key);1528 s.writeObject(v);1529 }1530 }1531 s.writeObject(null);1532 }1533 1534 /**1535 * Reconstitute the map from a stream.1536 */1537 private void readObject(final java.io.ObjectInputStream s)1538 throws java.io.IOException, ClassNotFoundException {1539 // Read in the Comparator and any hidden stuff1540 s.defaultReadObject();1541 // Reset transients1542 initialize();1543 1544 /*1545 * This is nearly identical to buildFromSorted, but is1546 * distinct because readObject calls can't be nicely adapted1547 * as the kind of iterator needed by buildFromSorted. (They1548 * can be, but doing so requires type cheats and/or creation1549 * of adaptor classes.) It is simpler to just adapt the code.1550 */1551 1552 HeadIndex<K,V> h = head;1553 Node<K,V> basepred = h.node;1554 ArrayList<Index<K,V>> preds = new ArrayList<Index<K,V>>();1555 for (int i = 0; i <= h.level; ++i)1556 preds.add(null);1557 Index<K,V> q = h;1558 for (int i = h.level; i > 0; --i) {1559 preds.set(i, q);1560 q = q.down;1561 }1562 1563 for (;;) {1564 Object k = s.readObject();1565 if (k == null)1566 break;1567 Object v = s.readObject();1568 if (v == null)1569 throw new NullPointerException();1570 K key = (K) k;1571 V val = (V) v;1572 int j = randomLevel();1573 if (j > h.level) j = h.level + 1;1574 Node<K,V> z = new Node<K,V>(key, val, null);1575 basepred.next = z;1576 basepred = z;1577 if (j > 0) {1578 Index<K,V> idx = null;1579 for (int i = 1; i <= j; ++i) {1580 idx = new Index<K,V>(z, idx, null);1581 if (i > h.level)1582 h = new HeadIndex<K,V>(h.node, h, idx, i);1583 1584 if (i < preds.size()) {1585 preds.get(i).right = idx;1586 preds.set(i, idx);1587 } else1588 preds.add(idx);1589 }1590 }1591 }1592 head = h;1593 }1594 1595 /* ------ Map API methods ------ */1596 1597 /**1598 * Returns <tt>true</tt> if this map contains a mapping for the specified1599 * key.1600 *1601 * @param key key whose presence in this map is to be tested1602 * @return <tt>true</tt> if this map contains a mapping for the specified key1603 * @throws ClassCastException if the specified key cannot be compared1604 * with the keys currently in the map1605 * @throws NullPointerException if the specified key is null1606 */1607 public boolean containsKey(Object key) {1608 return doGet(key) != null;1609 }1610 1611 /**1612 * Returns the value to which the specified key is mapped,1613 * or {@code null} if this map contains no mapping for the key.1614 *1615 * <p>More formally, if this map contains a mapping from a key1616 * {@code k} to a value {@code v} such that {@code key} compares1617 * equal to {@code k} according to the map's ordering, then this1618 * method returns {@code v}; otherwise it returns {@code null}.1619 * (There can be at most one such mapping.)1620 *1621 * @throws ClassCastException if the specified key cannot be compared1622 * with the keys currently in the map1623 * @throws NullPointerException if the specified key is null1624 */1625 public V get(Object key) {1626 return doGet(key);1627 }1628 1629 /**1630 * Associates the specified value with the specified key in this map.1631 * If the map previously contained a mapping for the key, the old1632 * value is replaced.1633 *1634 * @param key key with which the specified value is to be associated1635 * @param value value to be associated with the specified key1636 * @return the previous value associated with the specified key, or1637 * <tt>null</tt> if there was no mapping for the key1638 * @throws ClassCastException if the specified key cannot be compared1639 * with the keys currently in the map1640 * @throws NullPointerException if the specified key or value is null1641 */1642 public V put(K key, V value) {1643 if (value == null)1644 throw new NullPointerException();1645 return doPut(key, value, false);1646 }1647 1648 /**1649 * Removes the mapping for the specified key from this map if present.1650 *1651 * @param key key for which mapping should be removed1652 * @return the previous value associated with the specified key, or1653 * <tt>null</tt> if there was no mapping for the key1654 * @throws ClassCastException if the specified key cannot be compared1655 * with the keys currently in the map1656 * @throws NullPointerException if the specified key is null1657 */1658 public V remove(Object key) {1659 return doRemove(key, null);1660 }1661 1662 /**1663 * Returns <tt>true</tt> if this map maps one or more keys to the1664 * specified value. This operation requires time linear in the1665 * map size. Additionally, it is possible for the map to change1666 * during execution of this method, in which case the returned1667 * result may be inaccurate.1668 *1669 * @param value value whose presence in this map is to be tested1670 * @return <tt>true</tt> if a mapping to <tt>value</tt> exists;1671 * <tt>false</tt> otherwise1672 * @throws NullPointerException if the specified value is null1673 */1674 public boolean containsValue(Object value) {1675 if (value == null)1676 throw new NullPointerException();1677 for (Node<K,V> n = findFirst(); n != null; n = n.next) {1678 V v = n.getValidValue();1679 if (v != null && value.equals(v))1680 return true;1681 }1682 return false;1683 }1684 1685 /**1686 * Returns the number of key-value mappings in this map. If this map1687 * contains more than <tt>Integer.MAX_VALUE</tt> elements, it1688 * returns <tt>Integer.MAX_VALUE</tt>.1689 *1690 * <p>Beware that, unlike in most collections, this method is1691 * <em>NOT</em> a constant-time operation. Because of the1692 * asynchronous nature of these maps, determining the current1693 * number of elements requires traversing them all to count them.1694 * Additionally, it is possible for the size to change during1695 * execution of this method, in which case the returned result1696 * will be inaccurate. Thus, this method is typically not very1697 * useful in concurrent applications.1698 *1699 * @return the number of elements in this map1700 */1701 public int size() {1702 long count = 0;1703 for (Node<K,V> n = findFirst(); n != null; n = n.next) {1704 if (n.getValidValue() != null)1705 ++count;1706 }1707 return (count >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) count;1708 }1709 1710 /**1711 * Returns <tt>true</tt> if this map contains no key-value mappings.1712 * @return <tt>true</tt> if this map contains no key-value mappings1713 */1714 public boolean isEmpty() {1715 return findFirst() == null;1716 }1717 1718 /**1719 * Removes all of the mappings from this map.1720 */1721 public void clear() {1722 initialize();1723 }1724 1725 /* ---------------- View methods -------------- */1726 1727 /*1728 * Note: Lazy initialization works for views because view classes1729 * are stateless/immutable so it doesn't matter wrt correctness if1730 * more than one is created (which will only rarely happen). Even1731 * so, the following idiom conservatively ensures that the method1732 * returns the one it created if it does so, not one created by1733 * another racing thread.1734 */1735 1736 /**1737 * Returns a {@link NavigableSet} view of the keys contained in this map.1738 * The set's iterator returns the keys in ascending order.1739 * The set is backed by the map, so changes to the map are1740 * reflected in the set, and vice-versa. The set supports element1741 * removal, which removes the corresponding mapping from the map,1742 * via the {@code Iterator.remove}, {@code Set.remove},1743 * {@code removeAll}, {@code retainAll}, and {@code clear}1744 * operations. It does not support the {@code add} or {@code addAll}1745 * operations.1746 *1747 * <p>The view's {@code iterator} is a "weakly consistent" iterator1748 * that will never throw {@link ConcurrentModificationException},1749 * and guarantees to traverse elements as they existed upon1750 * construction of the iterator, and may (but is not guaranteed to)1751 * reflect any modifications subsequent to construction.1752 *1753 * <p>This method is equivalent to method {@code navigableKeySet}.1754 *1755 * @return a navigable set view of the keys in this map1756 */1757 public NavigableSet<K> keySet() {1758 KeySet ks = keySet;1759 return (ks != null) ? ks : (keySet = new KeySet(this));1760 }1761 1762 public NavigableSet<K> navigableKeySet() {1763 KeySet ks = keySet;1764 return (ks != null) ? ks : (keySet = new KeySet(this));1765 }1766 1767 /**1768 * Returns a {@link Collection} view of the values contained in this map.1769 * The collection's iterator returns the values in ascending order1770 * of the corresponding keys.1771 * The collection is backed by the map, so changes to the map are1772 * reflected in the collection, and vice-versa. The collection1773 * supports element removal, which removes the corresponding1774 * mapping from the map, via the <tt>Iterator.remove</tt>,1775 * <tt>Collection.remove</tt>, <tt>removeAll</tt>,1776 * <tt>retainAll</tt> and <tt>clear</tt> operations. It does not1777 * support the <tt>add</tt> or <tt>addAll</tt> operations.1778 *1779 * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator1780 * that will never throw {@link ConcurrentModificationException},1781 * and guarantees to traverse elements as they existed upon1782 * construction of the iterator, and may (but is not guaranteed to)1783 * reflect any modifications subsequent to construction.1784 */1785 public Collection<V> values() {1786 Values vs = values;1787 return (vs != null) ? vs : (values = new Values(this));1788 }1789 1790 /**1791 * Returns a {@link Set} view of the mappings contained in this map.1792 * The set's iterator returns the entries in ascending key order.1793 * The set is backed by the map, so changes to the map are1794 * reflected in the set, and vice-versa. The set supports element1795 * removal, which removes the corresponding mapping from the map,1796 * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,1797 * <tt>removeAll</tt>, <tt>retainAll</tt> and <tt>clear</tt>1798 * operations. It does not support the <tt>add</tt> or1799 * <tt>addAll</tt> operations.1800 *1801 * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator1802 * that will never throw {@link ConcurrentModificationException},1803 * and guarantees to traverse elements as they existed upon1804 * construction of the iterator, and may (but is not guaranteed to)1805 * reflect any modifications subsequent to construction.1806 *1807 * <p>The <tt>Map.Entry</tt> elements returned by1808 * <tt>iterator.next()</tt> do <em>not</em> support the1809 * <tt>setValue</tt> operation.1810 *1811 * @return a set view of the mappings contained in this map,1812 * sorted in ascending key order1813 */1814 public Set<Map.Entry<K,V>> entrySet() {1815 EntrySet es = entrySet;1816 return (es != null) ? es : (entrySet = new EntrySet(this));1817 }1818 1819 public ConcurrentNavigableMap<K,V> descendingMap() {1820 ConcurrentNavigableMap<K,V> dm = descendingMap;1821 return (dm != null) ? dm : (descendingMap = new SubMap<K,V>1822 (this, null, false, null, false, true));1823 }1824 1825 public NavigableSet<K> descendingKeySet() {1826 return descendingMap().navigableKeySet();1827 }1828 1829 /* ---------------- AbstractMap Overrides -------------- */1830 1831 /**1832 * Compares the specified object with this map for equality.1833 * Returns <tt>true</tt> if the given object is also a map and the1834 * two maps represent the same mappings. More formally, two maps1835 * <tt>m1</tt> and <tt>m2</tt> represent the same mappings if1836 * <tt>m1.entrySet().equals(m2.entrySet())</tt>. This1837 * operation may return misleading results if either map is1838 * concurrently modified during execution of this method.1839 *1840 * @param o object to be compared for equality with this map1841 * @return <tt>true</tt> if the specified object is equal to this map1842 */1843 public boolean equals(Object o) {1844 if (o == this)1845 return true;1846 if (!(o instanceof Map))1847 return false;1848 Map<?,?> m = (Map<?,?>) o;1849 try {1850 for (Map.Entry<K,V> e : this.entrySet())1851 if (! e.getValue().equals(m.get(e.getKey())))1852 return false;1853 for (Map.Entry<?,?> e : m.entrySet()) {1854 Object k = e.getKey();1855 Object v = e.getValue();1856 if (k == null || v == null || !v.equals(get(k)))1857 return false;1858 }1859 return true;1860 } catch (ClassCastException unused) {1861 return false;1862 } catch (NullPointerException unused) {1863 return false;1864 }1865 }1866 1867 /* ------ ConcurrentMap API methods ------ */1868 1869 /**1870 * {@inheritDoc}1871 *1872 * @return the previous value associated with the specified key,1873 * or <tt>null</tt> if there was no mapping for the key1874 * @throws ClassCastException if the specified key cannot be compared1875 * with the keys currently in the map1876 * @throws NullPointerException if the specified key or value is null1877 */1878 public V putIfAbsent(K key, V value) {1879 if (value == null)1880 throw new NullPointerException();1881 return doPut(key, value, true);1882 }1883 1884 /**1885 * {@inheritDoc}1886 *1887 * @throws ClassCastException if the specified key cannot be compared1888 * with the keys currently in the map1889 * @throws NullPointerException if the specified key is null1890 */1891 public boolean remove(Object key, Object value) {1892 if (key == null)1893 throw new NullPointerException();1894 if (value == null)1895 return false;1896 return doRemove(key, value) != null;1897 }1898 1899 /**1900 * {@inheritDoc}1901 *1902 * @throws ClassCastException if the specified key cannot be compared1903 * with the keys currently in the map1904 * @throws NullPointerException if any of the arguments are null1905 */1906 public boolean replace(K key, V oldValue, V newValue) {1907 if (oldValue == null || newValue == null)1908 throw new NullPointerException();1909 Comparable<? super K> k = comparable(key);1910 for (;;) {1911 Node<K,V> n = findNode(k);1912 if (n == null)1913 return false;1914 Object v = n.value;1915 if (v != null) {1916 if (!oldValue.equals(v))1917 return false;1918 if (n.casValue(v, newValue))1919 return true;1920 }1921 }1922 }1923 1924 /**1925 * {@inheritDoc}1926 *1927 * @return the previous value associated with the specified key,1928 * or <tt>null</tt> if there was no mapping for the key1929 * @throws ClassCastException if the specified key cannot be compared1930 * with the keys currently in the map1931 * @throws NullPointerException if the specified key or value is null1932 */1933 public V replace(K key, V value) {1934 if (value == null)1935 throw new NullPointerException();1936 Comparable<? super K> k = comparable(key);1937 for (;;) {1938 Node<K,V> n = findNode(k);1939 if (n == null)1940 return null;1941 Object v = n.value;1942 if (v != null && n.casValue(v, value))1943 return (V)v;1944 }1945 }1946 1947 /* ------ SortedMap API methods ------ */1948 1949 public Comparator<? super K> comparator() {1950 return comparator;1951 }1952 1953 /**1954 * @throws NoSuchElementException {@inheritDoc}1955 */1956 public K firstKey() {1957 Node<K,V> n = findFirst();1958 if (n == null)1959 throw new NoSuchElementException();1960 return n.key;1961 }1962 1963 /**1964 * @throws NoSuchElementException {@inheritDoc}1965 */1966 public K lastKey() {1967 Node<K,V> n = findLast();1968 if (n == null)1969 throw new NoSuchElementException();1970 return n.key;1971 }1972 1973 /**1974 * @throws ClassCastException {@inheritDoc}1975 * @throws NullPointerException if {@code fromKey} or {@code toKey} is null1976 * @throws IllegalArgumentException {@inheritDoc}1977 */1978 public ConcurrentNavigableMap<K,V> subMap(K fromKey,1979 boolean fromInclusive,1980 K toKey,1981 boolean toInclusive) {1982 if (fromKey == null || toKey == null)1983 throw new NullPointerException();1984 return new SubMap<K,V>1985 (this, fromKey, fromInclusive, toKey, toInclusive, false);1986 }1987 1988 /**1989 * @throws ClassCastException {@inheritDoc}1990 * @throws NullPointerException if {@code toKey} is null1991 * @throws IllegalArgumentException {@inheritDoc}1992 */1993 public ConcurrentNavigableMap<K,V> headMap(K toKey,1994 boolean inclusive) {1995 if (toKey == null)1996 throw new NullPointerException();1997 return new SubMap<K,V>1998 (this, null, false, toKey, inclusive, false);1999 }2000 2001 /**2002 * @throws ClassCastException {@inheritDoc}2003 * @throws NullPointerException if {@code fromKey} is null2004 * @throws IllegalArgumentException {@inheritDoc}2005 */2006 public ConcurrentNavigableMap<K,V> tailMap(K fromKey,2007 boolean inclusive) {2008 if (fromKey == null)2009 throw new NullPointerException();2010 return new SubMap<K,V>2011 (this, fromKey, inclusive, null, false, false);2012 }2013 2014 /**2015 * @throws ClassCastException {@inheritDoc}2016 * @throws NullPointerException if {@code fromKey} or {@code toKey} is null2017 * @throws IllegalArgumentException {@inheritDoc}2018 */2019 public ConcurrentNavigableMap<K,V> subMap(K fromKey, K toKey) {2020 return subMap(fromKey, true, toKey, false);2021 }2022 2023 /**2024 * @throws ClassCastException {@inheritDoc}2025 * @throws NullPointerException if {@code toKey} is null2026 * @throws IllegalArgumentException {@inheritDoc}2027 */2028 public ConcurrentNavigableMap<K,V> headMap(K toKey) {2029 return headMap(toKey, false);2030 }2031 2032 /**2033 * @throws ClassCastException {@inheritDoc}2034 * @throws NullPointerException if {@code fromKey} is null2035 * @throws IllegalArgumentException {@inheritDoc}2036 */2037 public ConcurrentNavigableMap<K,V> tailMap(K fromKey) {2038 return tailMap(fromKey, true);2039 }2040 2041 /* ---------------- Relational operations -------------- */2042 2043 /**2044 * Returns a key-value mapping associated with the greatest key2045 * strictly less than the given key, or <tt>null</tt> if there is2046 * no such key. The returned entry does <em>not</em> support the2047 * <tt>Entry.setValue</tt> method.2048 *2049 * @throws ClassCastException {@inheritDoc}2050 * @throws NullPointerException if the specified key is null2051 */2052 public Map.Entry<K,V> lowerEntry(K key) {2053 return getNear(key, LT);2054 }2055 2056 /**2057 * @throws ClassCastException {@inheritDoc}2058 * @throws NullPointerException if the specified key is null2059 */2060 public K lowerKey(K key) {2061 Node<K,V> n = findNear(key, LT);2062 return (n == null) ? null : n.key;2063 }2064 2065 /**2066 * Returns a key-value mapping associated with the greatest key2067 * less than or equal to the given key, or <tt>null</tt> if there2068 * is no such key. The returned entry does <em>not</em> support2069 * the <tt>Entry.setValue</tt> method.2070 *2071 * @param key the key2072 * @throws ClassCastException {@inheritDoc}2073 * @throws NullPointerException if the specified key is null2074 */2075 public Map.Entry<K,V> floorEntry(K key) {2076 return getNear(key, LT|EQ);2077 }2078 2079 /**2080 * @param key the key2081 * @throws ClassCastException {@inheritDoc}2082 * @throws NullPointerException if the specified key is null2083 */2084 public K floorKey(K key) {2085 Node<K,V> n = findNear(key, LT|EQ);2086 return (n == null) ? null : n.key;2087 }2088 2089 /**2090 * Returns a key-value mapping associated with the least key2091 * greater than or equal to the given key, or <tt>null</tt> if2092 * there is no such entry. The returned entry does <em>not</em>2093 * support the <tt>Entry.setValue</tt> method.2094 *2095 * @throws ClassCastException {@inheritDoc}2096 * @throws NullPointerException if the specified key is null2097 */2098 public Map.Entry<K,V> ceilingEntry(K key) {2099 return getNear(key, GT|EQ);2100 }2101 2102 /**2103 * @throws ClassCastException {@inheritDoc}2104 * @throws NullPointerException if the specified key is null2105 */2106 public K ceilingKey(K key) {2107 Node<K,V> n = findNear(key, GT|EQ);2108 return (n == null) ? null : n.key;2109 }2110 2111 /**2112 * Returns a key-value mapping associated with the least key2113 * strictly greater than the given key, or <tt>null</tt> if there2114 * is no such key. The returned entry does <em>not</em> support2115 * the <tt>Entry.setValue</tt> method.2116 *2117 * @param key the key2118 * @throws ClassCastException {@inheritDoc}2119 * @throws NullPointerException if the specified key is null2120 */2121 public Map.Entry<K,V> higherEntry(K key) {2122 return getNear(key, GT);2123 }2124 2125 /**2126 * @param key the key2127 * @throws ClassCastException {@inheritDoc}2128 * @throws NullPointerException if the specified key is null2129 */2130 public K higherKey(K key) {2131 Node<K,V> n = findNear(key, GT);2132 return (n == null) ? null : n.key;2133 }2134 2135 /**2136 * Returns a key-value mapping associated with the least2137 * key in this map, or <tt>null</tt> if the map is empty.2138 * The returned entry does <em>not</em> support2139 * the <tt>Entry.setValue</tt> method.2140 */2141 public Map.Entry<K,V> firstEntry() {2142 for (;;) {2143 Node<K,V> n = findFirst();2144 if (n == null)2145 return null;2146 AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();2147 if (e != null)2148 return e;2149 }2150 }2151 2152 /**2153 * Returns a key-value mapping associated with the greatest2154 * key in this map, or <tt>null</tt> if the map is empty.2155 * The returned entry does <em>not</em> support2156 * the <tt>Entry.setValue</tt> method.2157 */2158 public Map.Entry<K,V> lastEntry() {2159 for (;;) {2160 Node<K,V> n = findLast();2161 if (n == null)2162 return null;2163 AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();2164 if (e != null)2165 return e;2166 }2167 }2168 2169 /**2170 * Removes and returns a key-value mapping associated with2171 * the least key in this map, or <tt>null</tt> if the map is empty.2172 * The returned entry does <em>not</em> support2173 * the <tt>Entry.setValue</tt> method.2174 */2175 public Map.Entry<K,V> pollFirstEntry() {2176 return doRemoveFirstEntry();2177 }2178 2179 /**2180 * Removes and returns a key-value mapping associated with2181 * the greatest key in this map, or <tt>null</tt> if the map is empty.2182 * The returned entry does <em>not</em> support2183 * the <tt>Entry.setValue</tt> method.2184 */2185 public Map.Entry<K,V> pollLastEntry() {2186 return doRemoveLastEntry();2187 }2188 2189 2190 /* ---------------- Iterators -------------- */2191 2192 /**2193 * Base of iterator classes:2194 */2195 abstract class Iter<T> implements Iterator<T> {2196 /** the last node returned by next() */2197 Node<K,V> lastReturned;2198 /** the next node to return from next(); */2199 Node<K,V> next;2200 /** Cache of next value field to maintain weak consistency */2201 V nextValue;2202 2203 /** Initializes ascending iterator for entire range. */2204 Iter() {2205 for (;;) {2206 next = findFirst();2207 if (next == null)2208 break;2209 Object x = next.value;2210 if (x != null && x != next) {2211 nextValue = (V) x;2212 break;2213 }2214 }2215 }2216 2217 public final boolean hasNext() {2218 return next != null;2219 }2220 2221 /** Advances next to higher entry. */2222 final void advance() {2223 if (next == null)2224 throw new NoSuchElementException();2225 lastReturned = next;2226 for (;;) {2227 next = next.next;2228 if (next == null)2229 break;2230 Object x = next.value;2231 if (x != null && x != next) {2232 nextValue = (V) x;2233 break;2234 }2235 }2236 }2237 2238 public void remove() {2239 Node<K,V> l = lastReturned;2240 if (l == null)2241 throw new IllegalStateException();2242 // It would not be worth all of the overhead to directly2243 // unlink from here. Using remove is fast enough.2244 ConcurrentSkipListMap.this.remove(l.key);2245 lastReturned = null;2246 }2247 2248 }2249 2250 final class ValueIterator extends Iter<V> {2251 public V next() {2252 V v = nextValue;2253 advance();2254 return v;2255 }2256 }2257 2258 final class KeyIterator extends Iter<K> {2259 public K next() {2260 Node<K,V> n = next;2261 advance();2262 return n.key;2263 }2264 }2265 2266 final class EntryIterator extends Iter<Map.Entry<K,V>> {2267 public Map.Entry<K,V> next() {2268 Node<K,V> n = next;2269 V v = nextValue;2270 advance();2271 return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);2272 }2273 }2274 2275 // Factory methods for iterators needed by ConcurrentSkipListSet etc2276 2277 Iterator<K> keyIterator() {2278 return new KeyIterator();2279 }2280 2281 Iterator<V> valueIterator() {2282 return new ValueIterator();2283 }2284 2285 Iterator<Map.Entry<K,V>> entryIterator() {2286 return new EntryIterator();2287 }2288 2289 /* ---------------- View Classes -------------- */2290 2291 /*2292 * View classes are static, delegating to a ConcurrentNavigableMap2293 * to allow use by SubMaps, which outweighs the ugliness of2294 * needing type-tests for Iterator methods.2295 */2296 2297 static final <E> List<E> toList(Collection<E> c) {2298 // Using size() here would be a pessimization.2299 List<E> list = new ArrayList<E>();2300 for (E e : c)2301 list.add(e);2302 return list;2303 }2304 2305 static final class KeySet<E>2306 extends AbstractSet<E> implements NavigableSet<E> {2307 private final ConcurrentNavigableMap<E,Object> m;2308 KeySet(ConcurrentNavigableMap<E,Object> map) { m = map; }2309 public int size() { return m.size(); }2310 public boolean isEmpty() { return m.isEmpty(); }2311 public boolean contains(Object o) { return m.containsKey(o); }2312 public boolean remove(Object o) { return m.remove(o) != null; }2313 public void clear() { m.clear(); }2314 public E lower(E e) { return m.lowerKey(e); }2315 public E floor(E e) { return m.floorKey(e); }2316 public E ceiling(E e) { return m.ceilingKey(e); }2317 public E higher(E e) { return m.higherKey(e); }2318 public Comparator<? super E> comparator() { return m.comparator(); }2319 public E first() { return m.firstKey(); }2320 public E last() { return m.lastKey(); }2321 public E pollFirst() {2322 Map.Entry<E,Object> e = m.pollFirstEntry();2323 return (e == null) ? null : e.getKey();2324 }2325 public E pollLast() {2326 Map.Entry<E,Object> e = m.pollLastEntry();2327 return (e == null) ? null : e.getKey();2328 }2329 public Iterator<E> iterator() {2330 if (m instanceof ConcurrentSkipListMap)2331 return ((ConcurrentSkipListMap<E,Object>)m).keyIterator();2332 else2333 return ((ConcurrentSkipListMap.SubMap<E,Object>)m).keyIterator();2334 }2335 public boolean equals(Object o) {2336 if (o == this)2337 return true;2338 if (!(o instanceof Set))2339 return false;2340 Collection<?> c = (Collection<?>) o;2341 try {2342 return containsAll(c) && c.containsAll(this);2343 } catch (ClassCastException unused) {2344 return false;2345 } catch (NullPointerException unused) {2346 return false;2347 }2348 }2349 public Object[] toArray() { return toList(this).toArray(); }2350 public <T> T[] toArray(T[] a) { return toList(this).toArray(a); }2351 public Iterator<E> descendingIterator() {2352 return descendingSet().iterator();2353 }2354 public NavigableSet<E> subSet(E fromElement,2355 boolean fromInclusive,2356 E toElement,2357 boolean toInclusive) {2358 return new KeySet<E>(m.subMap(fromElement, fromInclusive,2359 toElement, toInclusive));2360 }2361 public NavigableSet<E> headSet(E toElement, boolean inclusive) {2362 return new KeySet<E>(m.headMap(toElement, inclusive));2363 }2364 public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {2365 return new KeySet<E>(m.tailMap(fromElement, inclusive));2366 }2367 public NavigableSet<E> subSet(E fromElement, E toElement) {2368 return subSet(fromElement, true, toElement, false);2369 }2370 public NavigableSet<E> headSet(E toElement) {2371 return headSet(toElement, false);2372 }2373 public NavigableSet<E> tailSet(E fromElement) {2374 return tailSet(fromElement, true);2375 }2376 public NavigableSet<E> descendingSet() {2377 return new KeySet(m.descendingMap());2378 }2379 }2380 2381 static final class Values<E> extends AbstractCollection<E> {2382 private final ConcurrentNavigableMap<Object, E> m;2383 Values(ConcurrentNavigableMap<Object, E> map) {2384 m = map;2385 }2386 public Iterator<E> iterator() {2387 if (m instanceof ConcurrentSkipListMap)2388 return ((ConcurrentSkipListMap<Object,E>)m).valueIterator();2389 else2390 return ((SubMap<Object,E>)m).valueIterator();2391 }2392 public boolean isEmpty() {2393 return m.isEmpty();2394 }2395 public int size() {2396 return m.size();2397 }2398 public boolean contains(Object o) {2399 return m.containsValue(o);2400 }2401 public void clear() {2402 m.clear();2403 }2404 public Object[] toArray() { return toList(this).toArray(); }2405 public <T> T[] toArray(T[] a) { return toList(this).toArray(a); }2406 }2407 2408 static final class EntrySet<K1,V1> extends AbstractSet<Map.Entry<K1,V1>> {2409 private final ConcurrentNavigableMap<K1, V1> m;2410 EntrySet(ConcurrentNavigableMap<K1, V1> map) {2411 m = map;2412 }2413 2414 public Iterator<Map.Entry<K1,V1>> iterator() {2415 if (m instanceof ConcurrentSkipListMap)2416 return ((ConcurrentSkipListMap<K1,V1>)m).entryIterator();2417 else2418 return ((SubMap<K1,V1>)m).entryIterator();2419 }2420 2421 public boolean contains(Object o) {2422 if (!(o instanceof Map.Entry))2423 return false;2424 Map.Entry<K1,V1> e = (Map.Entry<K1,V1>)o;2425 V1 v = m.get(e.getKey());2426 return v != null && v.equals(e.getValue());2427 }2428 public boolean remove(Object o) {2429 if (!(o instanceof Map.Entry))2430 return false;2431 Map.Entry<K1,V1> e = (Map.Entry<K1,V1>)o;2432 return m.remove(e.getKey(),2433 e.getValue());2434 }2435 public boolean isEmpty() {2436 return m.isEmpty();2437 }2438 public int size() {2439 return m.size();2440 }2441 public void clear() {2442 m.clear();2443 }2444 public boolean equals(Object o) {2445 if (o == this)2446 return true;2447 if (!(o instanceof Set))2448 return false;2449 Collection<?> c = (Collection<?>) o;2450 try {2451 return containsAll(c) && c.containsAll(this);2452 } catch (ClassCastException unused) {2453 return false;2454 } catch (NullPointerException unused) {2455 return false;2456 }2457 }2458 public Object[] toArray() { return toList(this).toArray(); }2459 public <T> T[] toArray(T[] a) { return toList(this).toArray(a); }2460 }2461 2462 /**2463 * Submaps returned by {@link ConcurrentSkipListMap} submap operations2464 * represent a subrange of mappings of their underlying2465 * maps. Instances of this class support all methods of their2466 * underlying maps, differing in that mappings outside their range are2467 * ignored, and attempts to add mappings outside their ranges result2468 * in {@link IllegalArgumentException}. Instances of this class are2469 * constructed only using the <tt>subMap</tt>, <tt>headMap</tt>, and2470 * <tt>tailMap</tt> methods of their underlying maps.2471 *2472 * @serial include2473 */2474 static final class SubMap<K,V> extends AbstractMap<K,V>2475 implements ConcurrentNavigableMap<K,V>, Cloneable,2476 java.io.Serializable {2477 private static final long serialVersionUID = -7647078645895051609L;2478 2479 /** Underlying map */2480 private final ConcurrentSkipListMap<K,V> m;2481 /** lower bound key, or null if from start */2482 private final K lo;2483 /** upper bound key, or null if to end */2484 private final K hi;2485 /** inclusion flag for lo */2486 private final boolean loInclusive;2487 /** inclusion flag for hi */2488 private final boolean hiInclusive;2489 /** direction */2490 private final boolean isDescending;2491 2492 // Lazily initialized view holders2493 private transient KeySet<K> keySetView;2494 private transient Set<Map.Entry<K,V>> entrySetView;2495 private transient Collection<V> valuesView;2496 2497 /**2498 * Creates a new submap, initializing all fields2499 */2500 SubMap(ConcurrentSkipListMap<K,V> map,2501 K fromKey, boolean fromInclusive,2502 K toKey, boolean toInclusive,2503 boolean isDescending) {2504 if (fromKey != null && toKey != null &&2505 map.compare(fromKey, toKey) > 0)2506 throw new IllegalArgumentException("inconsistent range");2507 this.m = map;2508 this.lo = fromKey;2509 this.hi = toKey;2510 this.loInclusive = fromInclusive;2511 this.hiInclusive = toInclusive;2512 this.isDescending = isDescending;2513 }2514 2515 /* ---------------- Utilities -------------- */2516 2517 private boolean tooLow(K key) {2518 if (lo != null) {2519 int c = m.compare(key, lo);2520 if (c < 0 || (c == 0 && !loInclusive))2521 return true;2522 }2523 return false;2524 }2525 2526 private boolean tooHigh(K key) {2527 if (hi != null) {2528 int c = m.compare(key, hi);2529 if (c > 0 || (c == 0 && !hiInclusive))2530 return true;2531 }2532 return false;2533 }2534 2535 private boolean inBounds(K key) {2536 return !tooLow(key) && !tooHigh(key);2537 }2538 2539 private void checkKeyBounds(K key) throws IllegalArgumentException {2540 if (key == null)2541 throw new NullPointerException();2542 if (!inBounds(key))2543 throw new IllegalArgumentException("key out of range");2544 }2545 2546 /**2547 * Returns true if node key is less than upper bound of range2548 */2549 private boolean isBeforeEnd(ConcurrentSkipListMap.Node<K,V> n) {2550 if (n == null)2551 return false;2552 if (hi == null)2553 return true;2554 K k = n.key;2555 if (k == null) // pass by markers and headers2556 return true;2557 int c = m.compare(k, hi);2558 if (c > 0 || (c == 0 && !hiInclusive))2559 return false;2560 return true;2561 }2562 2563 /**2564 * Returns lowest node. This node might not be in range, so2565 * most usages need to check bounds2566 */2567 private ConcurrentSkipListMap.Node<K,V> loNode() {2568 if (lo == null)2569 return m.findFirst();2570 else if (loInclusive)2571 return m.findNear(lo, m.GT|m.EQ);2572 else2573 return m.findNear(lo, m.GT);2574 }2575 2576 /**2577 * Returns highest node. This node might not be in range, so2578 * most usages need to check bounds2579 */2580 private ConcurrentSkipListMap.Node<K,V> hiNode() {2581 if (hi == null)2582 return m.findLast();2583 else if (hiInclusive)2584 return m.findNear(hi, m.LT|m.EQ);2585 else2586 return m.findNear(hi, m.LT);2587 }2588 2589 /**2590 * Returns lowest absolute key (ignoring directonality)2591 */2592 private K lowestKey() {2593 ConcurrentSkipListMap.Node<K,V> n = loNode();2594 if (isBeforeEnd(n))2595 return n.key;2596 else2597 throw new NoSuchElementException();2598 }2599 2600 /**2601 * Returns highest absolute key (ignoring directonality)2602 */2603 private K highestKey() {2604 ConcurrentSkipListMap.Node<K,V> n = hiNode();2605 if (n != null) {2606 K last = n.key;2607 if (inBounds(last))2608 return last;2609 }2610 throw new NoSuchElementException();2611 }2612 2613 private Map.Entry<K,V> lowestEntry() {2614 for (;;) {2615 ConcurrentSkipListMap.Node<K,V> n = loNode();2616 if (!isBeforeEnd(n))2617 return null;2618 Map.Entry<K,V> e = n.createSnapshot();2619 if (e != null)2620 return e;2621 }2622 }2623 2624 private Map.Entry<K,V> highestEntry() {2625 for (;;) {2626 ConcurrentSkipListMap.Node<K,V> n = hiNode();2627 if (n == null || !inBounds(n.key))2628 return null;2629 Map.Entry<K,V> e = n.createSnapshot();2630 if (e != null)2631 return e;2632 }2633 }2634 2635 private Map.Entry<K,V> removeLowest() {2636 for (;;) {2637 Node<K,V> n = loNode();2638 if (n == null)2639 return null;2640 K k = n.key;2641 if (!inBounds(k))2642 return null;2643 V v = m.doRemove(k, null);2644 if (v != null)2645 return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);2646 }2647 }2648 2649 private Map.Entry<K,V> removeHighest() {2650 for (;;) {2651 Node<K,V> n = hiNode();2652 if (n == null)2653 return null;2654 K k = n.key;2655 if (!inBounds(k))2656 return null;2657 V v = m.doRemove(k, null);2658 if (v != null)2659 return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);2660 }2661 }2662 2663 /**2664 * Submap version of ConcurrentSkipListMap.getNearEntry2665 */2666 private Map.Entry<K,V> getNearEntry(K key, int rel) {2667 if (isDescending) { // adjust relation for direction2668 if ((rel & m.LT) == 0)2669 rel |= m.LT;2670 else2671 rel &= ~m.LT;2672 }2673 if (tooLow(key))2674 return ((rel & m.LT) != 0) ? null : lowestEntry();2675 if (tooHigh(key))2676 return ((rel & m.LT) != 0) ? highestEntry() : null;2677 for (;;) {2678 Node<K,V> n = m.findNear(key, rel);2679 if (n == null || !inBounds(n.key))2680 return null;2681 K k = n.key;2682 V v = n.getValidValue();2683 if (v != null)2684 return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);2685 }2686 }2687 2688 // Almost the same as getNearEntry, except for keys2689 private K getNearKey(K key, int rel) {2690 if (isDescending) { // adjust relation for direction2691 if ((rel & m.LT) == 0)2692 rel |= m.LT;2693 else2694 rel &= ~m.LT;2695 }2696 if (tooLow(key)) {2697 if ((rel & m.LT) == 0) {2698 ConcurrentSkipListMap.Node<K,V> n = loNode();2699 if (isBeforeEnd(n))2700 return n.key;2701 }2702 return null;2703 }2704 if (tooHigh(key)) {2705 if ((rel & m.LT) != 0) {2706 ConcurrentSkipListMap.Node<K,V> n = hiNode();2707 if (n != null) {2708 K last = n.key;2709 if (inBounds(last))2710 return last;2711 }2712 }2713 return null;2714 }2715 for (;;) {2716 Node<K,V> n = m.findNear(key, rel);2717 if (n == null || !inBounds(n.key))2718 return null;2719 K k = n.key;2720 V v = n.getValidValue();2721 if (v != null)2722 return k;2723 }2724 }2725 2726 /* ---------------- Map API methods -------------- */2727 2728 public boolean containsKey(Object key) {2729 if (key == null) throw new NullPointerException();2730 K k = (K)key;2731 return inBounds(k) && m.containsKey(k);2732 }2733 2734 public V get(Object key) {2735 if (key == null) throw new NullPointerException();2736 K k = (K)key;2737 return ((!inBounds(k)) ? null : m.get(k));2738 }2739 2740 public V put(K key, V value) {2741 checkKeyBounds(key);2742 return m.put(key, value);2743 }2744 2745 public V remove(Object key) {2746 K k = (K)key;2747 return (!inBounds(k)) ? null : m.remove(k);2748 }2749 2750 public int size() {2751 long count = 0;2752 for (ConcurrentSkipListMap.Node<K,V> n = loNode();2753 isBeforeEnd(n);2754 n = n.next) {2755 if (n.getValidValue() != null)2756 ++count;2757 }2758 return count >= Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)count;2759 }2760 2761 public boolean isEmpty() {2762 return !isBeforeEnd(loNode());2763 }2764 2765 public boolean containsValue(Object value) {2766 if (value == null)2767 throw new NullPointerException();2768 for (ConcurrentSkipListMap.Node<K,V> n = loNode();2769 isBeforeEnd(n);2770 n = n.next) {2771 V v = n.getValidValue();2772 if (v != null && value.equals(v))2773 return true;2774 }2775 return false;2776 }2777 2778 public void clear() {2779 for (ConcurrentSkipListMap.Node<K,V> n = loNode();2780 isBeforeEnd(n);2781 n = n.next) {2782 if (n.getValidValue() != null)2783 m.remove(n.key);2784 }2785 }2786 2787 /* ---------------- ConcurrentMap API methods -------------- */2788 2789 public V putIfAbsent(K key, V value) {2790 checkKeyBounds(key);2791 return m.putIfAbsent(key, value);2792 }2793 2794 public boolean remove(Object key, Object value) {2795 K k = (K)key;2796 return inBounds(k) && m.remove(k, value);2797 }2798 2799 public boolean replace(K key, V oldValue, V newValue) {2800 checkKeyBounds(key);2801 return m.replace(key, oldValue, newValue);2802 }2803 2804 public V replace(K key, V value) {2805 checkKeyBounds(key);2806 return m.replace(key, value);2807 }2808 2809 /* ---------------- SortedMap API methods -------------- */2810 2811 public Comparator<? super K> comparator() {2812 Comparator<? super K> cmp = m.comparator();2813 if (isDescending)2814 return Collections.reverseOrder(cmp);2815 else2816 return cmp;2817 }2818 2819 /**2820 * Utility to create submaps, where given bounds override2821 * unbounded(null) ones and/or are checked against bounded ones.2822 */2823 private SubMap<K,V> newSubMap(K fromKey,2824 boolean fromInclusive,2825 K toKey,2826 boolean toInclusive) {2827 if (isDescending) { // flip senses2828 K tk = fromKey;2829 fromKey = toKey;2830 toKey = tk;2831 boolean ti = fromInclusive;2832 fromInclusive = toInclusive;2833 toInclusive = ti;2834 }2835 if (lo != null) {2836 if (fromKey == null) {2837 fromKey = lo;2838 fromInclusive = loInclusive;2839 }2840 else {2841 int c = m.compare(fromKey, lo);2842 if (c < 0 || (c == 0 && !loInclusive && fromInclusive))2843 throw new IllegalArgumentException("key out of range");2844 }2845 }2846 if (hi != null) {2847 if (toKey == null) {2848 toKey = hi;2849 toInclusive = hiInclusive;2850 }2851 else {2852 int c = m.compare(toKey, hi);2853 if (c > 0 || (c == 0 && !hiInclusive && toInclusive))2854 throw new IllegalArgumentException("key out of range");2855 }2856 }2857 return new SubMap<K,V>(m, fromKey, fromInclusive,2858 toKey, toInclusive, isDescending);2859 }2860 2861 public SubMap<K,V> subMap(K fromKey,2862 boolean fromInclusive,2863 K toKey,2864 boolean toInclusive) {2865 if (fromKey == null || toKey == null)2866 throw new NullPointerException();2867 return newSubMap(fromKey, fromInclusive, toKey, toInclusive);2868 }2869 2870 public SubMap<K,V> headMap(K toKey,2871 boolean inclusive) {2872 if (toKey == null)2873 throw new NullPointerException();2874 return newSubMap(null, false, toKey, inclusive);2875 }2876 2877 public SubMap<K,V> tailMap(K fromKey,2878 boolean inclusive) {2879 if (fromKey == null)2880 throw new NullPointerException();2881 return newSubMap(fromKey, inclusive, null, false);2882 }2883 2884 public SubMap<K,V> subMap(K fromKey, K toKey) {2885 return subMap(fromKey, true, toKey, false);2886 }2887 2888 public SubMap<K,V> headMap(K toKey) {2889 return headMap(toKey, false);2890 }2891 2892 public SubMap<K,V> tailMap(K fromKey) {2893 return tailMap(fromKey, true);2894 }2895 2896 public SubMap<K,V> descendingMap() {2897 return new SubMap<K,V>(m, lo, loInclusive,2898 hi, hiInclusive, !isDescending);2899 }2900 2901 /* ---------------- Relational methods -------------- */2902 2903 public Map.Entry<K,V> ceilingEntry(K key) {2904 return getNearEntry(key, (m.GT|m.EQ));2905 }2906 2907 public K ceilingKey(K key) {2908 return getNearKey(key, (m.GT|m.EQ));2909 }2910 2911 public Map.Entry<K,V> lowerEntry(K key) {2912 return getNearEntry(key, (m.LT));2913 }2914 2915 public K lowerKey(K key) {2916 return getNearKey(key, (m.LT));2917 }2918 2919 public Map.Entry<K,V> floorEntry(K key) {2920 return getNearEntry(key, (m.LT|m.EQ));2921 }2922 2923 public K floorKey(K key) {2924 return getNearKey(key, (m.LT|m.EQ));2925 }2926 2927 public Map.Entry<K,V> higherEntry(K key) {2928 return getNearEntry(key, (m.GT));2929 }2930 2931 public K higherKey(K key) {2932 return getNearKey(key, (m.GT));2933 }2934 2935 public K firstKey() {2936 return isDescending ? highestKey() : lowestKey();2937 }2938 2939 public K lastKey() {2940 return isDescending ? lowestKey() : highestKey();2941 }2942 2943 public Map.Entry<K,V> firstEntry() {2944 return isDescending ? highestEntry() : lowestEntry();2945 }2946 2947 public Map.Entry<K,V> lastEntry() {2948 return isDescending ? lowestEntry() : highestEntry();2949 }2950 2951 public Map.Entry<K,V> pollFirstEntry() {2952 return isDescending ? removeHighest() : removeLowest();2953 }2954 2955 public Map.Entry<K,V> pollLastEntry() {2956 return isDescending ? removeLowest() : removeHighest();2957 }2958 2959 /* ---------------- Submap Views -------------- */2960 2961 public NavigableSet<K> keySet() {2962 KeySet<K> ks = keySetView;2963 return (ks != null) ? ks : (keySetView = new KeySet(this));2964 }2965 2966 public NavigableSet<K> navigableKeySet() {2967 KeySet<K> ks = keySetView;2968 return (ks != null) ? ks : (keySetView = new KeySet(this));2969 }2970 2971 public Collection<V> values() {2972 Collection<V> vs = valuesView;2973 return (vs != null) ? vs : (valuesView = new Values(this));2974 }2975 2976 public Set<Map.Entry<K,V>> entrySet() {2977 Set<Map.Entry<K,V>> es = entrySetView;2978 return (es != null) ? es : (entrySetView = new EntrySet(this));2979 }2980 2981 public NavigableSet<K> descendingKeySet() {2982 return descendingMap().navigableKeySet();2983 }2984 2985 Iterator<K> keyIterator() {2986 return new SubMapKeyIterator();2987 }2988 2989 Iterator<V> valueIterator() {2990 return new SubMapValueIterator();2991 }2992 2993 Iterator<Map.Entry<K,V>> entryIterator() {2994 return new SubMapEntryIterator();2995 }2996 2997 /**2998 * Variant of main Iter class to traverse through submaps.2999 */3000 abstract class SubMapIter<T> implements Iterator<T> {3001 /** the last node returned by next() */3002 Node<K,V> lastReturned;3003 /** the next node to return from next(); */3004 Node<K,V> next;3005 /** Cache of next value field to maintain weak consistency */3006 V nextValue;3007 3008 SubMapIter() {3009 for (;;) {3010 next = isDescending ? hiNode() : loNode();3011 if (next == null)3012 break;3013 Object x = next.value;3014 if (x != null && x != next) {3015 if (! inBounds(next.key))3016 next = null;3017 else3018 nextValue = (V) x;3019 break;3020 }3021 }3022 }3023 3024 public final boolean hasNext() {3025 return next != null;3026 }3027 3028 final void advance() {3029 if (next == null)3030 throw new NoSuchElementException();3031 lastReturned = next;3032 if (isDescending)3033 descend();3034 else3035 ascend();3036 }3037 3038 private void ascend() {3039 for (;;) {3040 next = next.next;3041 if (next == null)3042 break;3043 Object x = next.value;3044 if (x != null && x != next) {3045 if (tooHigh(next.key))3046 next = null;3047 else3048 nextValue = (V) x;3049 break;3050 }3051 }3052 }3053 3054 private void descend() {3055 for (;;) {3056 next = m.findNear(lastReturned.key, LT);3057 if (next == null)3058 break;3059 Object x = next.value;3060 if (x != null && x != next) {3061 if (tooLow(next.key))3062 next = null;3063 else3064 nextValue = (V) x;3065 break;3066 }3067 }3068 }3069 3070 public void remove() {3071 Node<K,V> l = lastReturned;3072 if (l == null)3073 throw new IllegalStateException();3074 m.remove(l.key);3075 lastReturned = null;3076 }3077 3078 }3079 3080 final class SubMapValueIterator extends SubMapIter<V> {3081 public V next() {3082 V v = nextValue;3083 advance();3084 return v;3085 }3086 }3087 3088 final class SubMapKeyIterator extends SubMapIter<K> {3089 public K next() {3090 Node<K,V> n = next;3091 advance();3092 return n.key;3093 }3094 }3095 3096 final class SubMapEntryIterator extends SubMapIter<Map.Entry<K,V>> {3097 public Map.Entry<K,V> next() {3098 Node<K,V> n = next;3099 V v = nextValue;3100 advance();3101 return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);3102 }3103 }3104 }3105 3106 // Unsafe mechanics3107 private static final sun.misc.Unsafe UNSAFE;3108 private static final long headOffset;3109 static {3110 try {3111 UNSAFE = sun.misc.Unsafe.getUnsafe();3112 Class k = ConcurrentSkipListMap.class;3113 headOffset = UNSAFE.objectFieldOffset3114 (k.getDeclaredField("head"));3115 } catch (Exception e) {3116 throw new Error(e);3117 }3118 }3119 }
下面从ConcurrentSkipListMap的添加,删除,获取这3个方面对它进行分析。
1. 添加
下面以put(K key, V value)为例,对ConcurrentSkipListMap的添加方法进行说明。
public V put(K key, V value) { if (value == null) throw new NullPointerException(); return doPut(key, value, false);}
实际上,put()是通过doPut()将key-value键值对添加到ConcurrentSkipListMap中的。
doPut()的源码如下:
private V doPut(K kkey, V value, boolean onlyIfAbsent) { Comparable<? super K> key = comparable(kkey); for (;;) { // 找到key的前继节点 Node<K,V> b = findPredecessor(key); // 设置n为“key的前继节点的后继节点”,即n应该是“插入节点”的“后继节点” Node<K,V> n = b.next; for (;;) { if (n != null) { Node<K,V> f = n.next; // 如果两次获得的b.next不是相同的Node,就跳转到”外层for循环“,重新获得b和n后再遍历。 if (n != b.next) break; // v是“n的值” Object v = n.value; // 当n的值为null(意味着其它线程删除了n);此时删除b的下一个节点,然后跳转到”外层for循环“,重新获得b和n后再遍历。 if (v == null) { // n is deleted n.helpDelete(b, f); break; } // 如果其它线程删除了b;则跳转到”外层for循环“,重新获得b和n后再遍历。 if (v == n || b.value == null) // b is deleted break; // 比较key和n.key int c = key.compareTo(n.key); if (c > 0) { b = n; n = f; continue; } if (c == 0) { if (onlyIfAbsent || n.casValue(v, value)) return (V)v; else break; // restart if lost race to replace value } // else c < 0; fall through } // 新建节点(对应是“要插入的键值对”) Node<K,V> z = new Node<K,V>(kkey, value, n); // 设置“b的后继节点”为z if (!b.casNext(n, z)) break; // 多线程情况下,break才可能发生(其它线程对b进行了操作) // 随机获取一个level // 然后在“第1层”到“第level层”的链表中都插入新建节点 int level = randomLevel(); if (level > 0) insertIndex(z, level); return null; } }}
说明:doPut() 的作用就是将键值对添加到“跳表”中。
要想搞清doPut(),首先要弄清楚它的主干部分 —— 我们先单纯的只考虑“单线程的情况下,将key-value添加到跳表中”,即忽略“多线程相关的内容”。它的流程如下:
第1步:找到“插入位置”。
即,找到“key的前继节点(b)”和“key的后继节点(n)”;key是要插入节点的键。
第2步:新建并插入节点。
即,新建节点z(key对应的节点),并将新节点z插入到“跳表”中(设置“b的后继节点为z”,“z的后继节点为n”)。
第3步:更新跳表。
即,随机获取一个level,然后在“跳表”的第1层~第level层之间,每一层都插入节点z;在第level层之上就不再插入节点了。若level数值大于“跳表的层次”,则新建一层。
主干部分“对应的精简后的doPut()的代码”如下(仅供参考):
private V doPut(K kkey, V value, boolean onlyIfAbsent) { Comparable<? super K> key = comparable(kkey); for (;;) { // 找到key的前继节点 Node<K,V> b = findPredecessor(key); // 设置n为key的后继节点 Node<K,V> n = b.next; for (;;) { // 新建节点(对应是“要被插入的键值对”) Node<K,V> z = new Node<K,V>(kkey, value, n); // 设置“b的后继节点”为z b.casNext(n, z); // 随机获取一个level // 然后在“第1层”到“第level层”的链表中都插入新建节点 int level = randomLevel(); if (level > 0) insertIndex(z, level); return null; } }}
理清主干之后,剩余的工作就相对简单了。主要是上面几步的对应算法的具体实现,以及多线程相关情况的处理!
2. 删除
下面以remove(Object key)为例,对ConcurrentSkipListMap的删除方法进行说明。
public V remove(Object key) { return doRemove(key, null);}
实际上,remove()是通过doRemove()将ConcurrentSkipListMap中的key对应的键值对删除的。
doRemove()的源码如下:
final V doRemove(Object okey, Object value) { Comparable<? super K> key = comparable(okey); for (;;) { // 找到“key的前继节点” Node<K,V> b = findPredecessor(key); // 设置n为“b的后继节点”(即若key存在于“跳表中”,n就是key对应的节点) Node<K,V> n = b.next; for (;;) { if (n == null) return null; // f是“当前节点n的后继节点” Node<K,V> f = n.next; // 如果两次读取到的“b的后继节点”不同(其它线程操作了该跳表),则返回到“外层for循环”重新遍历。 if (n != b.next) // inconsistent read break; // 如果“当前节点n的值”变为null(其它线程操作了该跳表),则返回到“外层for循环”重新遍历。 Object v = n.value; if (v == null) { // n is deleted n.helpDelete(b, f); break; } // 如果“前继节点b”被删除(其它线程操作了该跳表),则返回到“外层for循环”重新遍历。 if (v == n || b.value == null) // b is deleted break; int c = key.compareTo(n.key); if (c < 0) return null; if (c > 0) { b = n; n = f; continue; } // 以下是c=0的情况 if (value != null && !value.equals(v)) return null; // 设置“当前节点n”的值为null if (!n.casValue(v, null)) break; // 设置“b的后继节点”为f if (!n.appendMarker(f) || !b.casNext(n, f)) findNode(key); // Retry via findNode else { // 清除“跳表”中每一层的key节点 findPredecessor(key); // Clean index // 如果“表头的右索引为空”,则将“跳表的层次”-1。 if (head.right == null) tryReduceLevel(); } return (V)v; } }}
说明:doRemove()的作用是删除跳表中的节点。
和doPut()一样,我们重点看doRemove()的主干部分,了解主干部分之后,其余部分就非常容易理解了。下面是“单线程的情况下,删除跳表中键值对的步骤”:
第1步:找到“被删除节点的位置”。
即,找到“key的前继节点(b)”,“key所对应的节点(n)”,“n的后继节点f”;key是要删除节点的键。
第2步:删除节点。
即,将“key所对应的节点n”从跳表中移除 -- 将“b的后继节点”设为“f”!
第3步:更新跳表。
即,遍历跳表,删除每一层的“key节点”(如果存在的话)。如果删除“key节点”之后,跳表的层次需要-1;则执行相应的操作!
主干部分“对应的精简后的doRemove()的代码”如下(仅供参考):
final V doRemove(Object okey, Object value) { Comparable<? super K> key = comparable(okey); for (;;) { // 找到“key的前继节点” Node<K,V> b = findPredecessor(key); // 设置n为“b的后继节点”(即若key存在于“跳表中”,n就是key对应的节点) Node<K,V> n = b.next; for (;;) { // f是“当前节点n的后继节点” Node<K,V> f = n.next; // 设置“当前节点n”的值为null n.casValue(v, null); // 设置“b的后继节点”为f b.casNext(n, f); // 清除“跳表”中每一层的key节点 findPredecessor(key); // 如果“表头的右索引为空”,则将“跳表的层次”-1。 if (head.right == null) tryReduceLevel(); return (V)v; } }}
3. 获取
下面以get(Object key)为例,对ConcurrentSkipListMap的获取方法进行说明。
public V get(Object key) { return doGet(key);}
doGet的源码如下:
private V doGet(Object okey) { Comparable<? super K> key = comparable(okey); for (;;) { // 找到“key对应的节点” Node<K,V> n = findNode(key); if (n == null) return null; Object v = n.value; if (v != null) return (V)v; }}
说明:doGet()是通过findNode()找到并返回节点的。
private Node<K,V> findNode(Comparable<? super K> key) { for (;;) { // 找到key的前继节点 Node<K,V> b = findPredecessor(key); // 设置n为“b的后继节点”(即若key存在于“跳表中”,n就是key对应的节点) Node<K,V> n = b.next; for (;;) { // 如果“n为null”,则跳转中不存在key对应的节点,直接返回null。 if (n == null) return null; Node<K,V> f = n.next; // 如果两次读取到的“b的后继节点”不同(其它线程操作了该跳表),则返回到“外层for循环”重新遍历。 if (n != b.next) // inconsistent read break; Object v = n.value; // 如果“当前节点n的值”变为null(其它线程操作了该跳表),则返回到“外层for循环”重新遍历。 if (v == null) { // n is deleted n.helpDelete(b, f); break; } if (v == n || b.value == null) // b is deleted break; // 若n是当前节点,则返回n。 int c = key.compareTo(n.key); if (c == 0) return n; // 若“节点n的key”小于“key”,则说明跳表中不存在key对应的节点,返回null if (c < 0) return null; // 若“节点n的key”大于“key”,则更新b和n,继续查找。 b = n; n = f; } }}
说明:findNode(key)的作用是在返回跳表中key对应的节点;存在则返回节点,不存在则返回null。
先弄清函数的主干部分,即抛开“多线程相关内容”,单纯的考虑单线程情况下,从跳表获取节点的算法。
第1步:找到“被删除节点的位置”。
根据findPredecessor()定位key所在的层次以及找到key的前继节点(b),然后找到b的后继节点n。
第2步:根据“key的前继节点(b)”和“key的前继节点的后继节点(n)”来定位“key对应的节点”。
具体是通过比较“n的键值”和“key”的大小。如果相等,则n就是所要查找的键。
ConcurrentSkipListMap示例
import java.util.*;import java.util.concurrent.*;/* * ConcurrentSkipListMap是“线程安全”的哈希表,而TreeMap是非线程安全的。 * * 下面是“多个线程同时操作并且遍历map”的示例 * (01) 当map是ConcurrentSkipListMap对象时,程序能正常运行。 * (02) 当map是TreeMap对象时,程序会产生ConcurrentModificationException异常。 * * @author skywang */public class ConcurrentSkipListMapDemo1 { // TODO: map是TreeMap对象时,程序会出错。 //private static Map<String, String> map = new TreeMap<String, String>(); private static Map<String, String> map = new ConcurrentSkipListMap<String, String>(); public static void main(String[] args) { // 同时启动两个线程对map进行操作! new MyThread("a").start(); new MyThread("b").start(); } private static void printAll() { String key, value; Iterator iter = map.entrySet().iterator(); while(iter.hasNext()) { Map.Entry entry = (Map.Entry)iter.next(); key = (String)entry.getKey(); value = (String)entry.getValue(); System.out.print("("+key+", "+value+"), "); } System.out.println(); } private static class MyThread extends Thread { MyThread(String name) { super(name); } @Override public void run() { int i = 0; while (i++ < 6) { // “线程名” + "序号" String val = Thread.currentThread().getName()+i; map.put(val, "0"); // 通过“Iterator”遍历map。 printAll(); } } }}
(某一次)运行结果:
(a1, 0), (a1, 0), (b1, 0), (b1, 0),(a1, 0), (b1, 0), (b2, 0), (a1, 0), (a1, 0), (a2, 0), (a2, 0), (b1, 0), (b1, 0), (b2, 0), (b2, 0), (b3, 0), (b3, 0), (a1, 0), (a2, 0), (a3, 0), (a1, 0), (b1, 0), (a2, 0), (b2, 0), (a3, 0), (b3, 0), (b1, 0), (b4, 0), (b2, 0), (a1, 0), (b3, 0), (a2, 0), (b4, 0), (a3, 0), (a1, 0), (a4, 0), (a2, 0), (b1, 0), (a3, 0), (b2, 0), (a4, 0), (b3, 0), (b1, 0), (b4, 0), (b2, 0), (b5, 0), (b3, 0), (a1, 0), (b4, 0), (a2, 0), (b5, 0), (a3, 0), (a1, 0), (a4, 0), (a2, 0), (a5, 0), (a3, 0), (b1, 0), (a4, 0), (b2, 0), (a5, 0), (b3, 0), (b1, 0), (b4, 0), (b2, 0), (b5, 0), (b3, 0), (b6, 0), (b4, 0), (a1, 0), (b5, 0), (a2, 0), (b6, 0), (a3, 0), (a4, 0), (a5, 0), (a6, 0), (b1, 0), (b2, 0), (b3, 0), (b4, 0), (b5, 0), (b6, 0),
结果说明:
示例程序中,启动两个线程(线程a和线程b)分别对ConcurrentSkipListMap进行操作。以线程a而言,它会先获取“线程名”+“序号”,然后将该字符串作为key,将“0”作为value,插入到ConcurrentSkipListMap中;接着,遍历并输出ConcurrentSkipListMap中的全部元素。 线程b的操作和线程a一样,只不过线程b的名字和线程a的名字不同。
当map是ConcurrentSkipListMap对象时,程序能正常运行。如果将map改为TreeMap时,程序会产生ConcurrentModificationException异常。
更多内容
1. Java多线程系列--“JUC集合”01之 框架
2. Java多线程系列目录(共xx篇)
- Java多线程系列--“JUC集合”05之 ConcurrentSkipListMap
- Java多线程系列--“JUC集合”05之 ConcurrentSkipListMap
- Java多线程系列--“JUC集合”05之 ConcurrentSkipListMap
- JUC集合-05之 ConcurrentSkipListMap
- Java多线程系列--“JUC集合”
- Java多线程系列--“JUC集合”04之 ConcurrentHashMap
- Java多线程系列--“JUC集合”01之 框架
- Java多线程系列--“JUC集合”01之 框架
- Java多线程系列--“JUC集合”02之 CopyOnWriteArrayList
- Java多线程系列--“JUC集合”03之 CopyOnWriteArraySet
- Java多线程系列--“JUC集合”04之 ConcurrentHashMap
- Java多线程系列--“JUC集合”01之 框架
- Java多线程系列--“JUC集合”02之 CopyOnWriteArrayList
- Java多线程系列--“JUC集合”03之 CopyOnWriteArraySet
- Java多线程系列--“JUC集合”04之 ConcurrentHashMap
- Java多线程系列--“JUC集合”06之 ConcurrentSkipListSet
- Java多线程系列--“JUC集合”07之 ArrayBlockingQueue
- Java多线程系列--“JUC集合”08之 LinkedBlockingQueue
- 20160803------排序、二维数组
- tushare数据格式转为PyalgoTrade所需格式
- AIDL(Android Interface Definition Language)
- 【Baltic2009】bzoj 1355 Radio Transmission
- javaIO
- Java多线程系列--“JUC集合”05之 ConcurrentSkipListMap
- 为了caffe(一)重现安装ubuntu14.04 64位版
- 算法导论—二叉树非递归遍历
- 第六章 6.1 函数基础
- 《Geekband》STL与泛型编程01
- C++ 单词接龙子程序
- 动态内存分配
- Java多线程系列--“JUC集合”06之 ConcurrentSkipListSet
- Android自助餐之插件化(使用Small框架)