ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/ConcurrentSkipListSet.java
Revision: 1.61
Committed: Mon Oct 1 00:10:53 2018 UTC (5 years, 8 months ago) by jsr166
Branch: MAIN
Changes since 1.60: +2 -2 lines
Log Message:
update to using jdk11 by default, except link to jdk10 javadocs;
sync @docRoot references in javadoc with upstream

File Contents

# Content
1 /*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain, as explained at
4 * http://creativecommons.org/publicdomain/zero/1.0/
5 */
6
7 package java.util.concurrent;
8
9 import java.lang.reflect.Field;
10 import java.util.AbstractSet;
11 import java.util.Collection;
12 import java.util.Collections;
13 import java.util.Comparator;
14 import java.util.Iterator;
15 import java.util.Map;
16 import java.util.NavigableSet;
17 import java.util.Set;
18 import java.util.SortedSet;
19 import java.util.Spliterator;
20
21 /**
22 * A scalable concurrent {@link NavigableSet} implementation based on
23 * a {@link ConcurrentSkipListMap}. The elements of the set are kept
24 * sorted according to their {@linkplain Comparable natural ordering},
25 * or by a {@link Comparator} provided at set creation time, depending
26 * on which constructor is used.
27 *
28 * <p>This implementation provides expected average <i>log(n)</i> time
29 * cost for the {@code contains}, {@code add}, and {@code remove}
30 * operations and their variants. Insertion, removal, and access
31 * operations safely execute concurrently by multiple threads.
32 *
33 * <p>Iterators and spliterators are
34 * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
35 *
36 * <p>Ascending ordered views and their iterators are faster than
37 * descending ones.
38 *
39 * <p>Beware that, unlike in most collections, the {@code size}
40 * method is <em>not</em> a constant-time operation. Because of the
41 * asynchronous nature of these sets, determining the current number
42 * of elements requires a traversal of the elements, and so may report
43 * inaccurate results if this collection is modified during traversal.
44 *
45 * <p>Bulk operations that add, remove, or examine multiple elements,
46 * such as {@link #addAll}, {@link #removeIf} or {@link #forEach},
47 * are <em>not</em> guaranteed to be performed atomically.
48 * For example, a {@code forEach} traversal concurrent with an {@code
49 * addAll} operation might observe only some of the added elements.
50 *
51 * <p>This class and its iterators implement all of the
52 * <em>optional</em> methods of the {@link Set} and {@link Iterator}
53 * interfaces. Like most other concurrent collection implementations,
54 * this class does not permit the use of {@code null} elements,
55 * because {@code null} arguments and return values cannot be reliably
56 * distinguished from the absence of elements.
57 *
58 * <p>This class is a member of the
59 * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
60 * Java Collections Framework</a>.
61 *
62 * @author Doug Lea
63 * @param <E> the type of elements maintained by this set
64 * @since 1.6
65 */
66 public class ConcurrentSkipListSet<E>
67 extends AbstractSet<E>
68 implements NavigableSet<E>, Cloneable, java.io.Serializable {
69
70 private static final long serialVersionUID = -2479143111061671589L;
71
72 /**
73 * The underlying map. Uses Boolean.TRUE as value for each
74 * element. This field is declared final for the sake of thread
75 * safety, which entails some ugliness in clone().
76 */
77 private final ConcurrentNavigableMap<E,Object> m;
78
79 /**
80 * Constructs a new, empty set that orders its elements according to
81 * their {@linkplain Comparable natural ordering}.
82 */
83 public ConcurrentSkipListSet() {
84 m = new ConcurrentSkipListMap<E,Object>();
85 }
86
87 /**
88 * Constructs a new, empty set that orders its elements according to
89 * the specified comparator.
90 *
91 * @param comparator the comparator that will be used to order this set.
92 * If {@code null}, the {@linkplain Comparable natural
93 * ordering} of the elements will be used.
94 */
95 public ConcurrentSkipListSet(Comparator<? super E> comparator) {
96 m = new ConcurrentSkipListMap<E,Object>(comparator);
97 }
98
99 /**
100 * Constructs a new set containing the elements in the specified
101 * collection, that orders its elements according to their
102 * {@linkplain Comparable natural ordering}.
103 *
104 * @param c The elements that will comprise the new set
105 * @throws ClassCastException if the elements in {@code c} are
106 * not {@link Comparable}, or are not mutually comparable
107 * @throws NullPointerException if the specified collection or any
108 * of its elements are null
109 */
110 public ConcurrentSkipListSet(Collection<? extends E> c) {
111 m = new ConcurrentSkipListMap<E,Object>();
112 addAll(c);
113 }
114
115 /**
116 * Constructs a new set containing the same elements and using the
117 * same ordering as the specified sorted set.
118 *
119 * @param s sorted set whose elements will comprise the new set
120 * @throws NullPointerException if the specified sorted set or any
121 * of its elements are null
122 */
123 public ConcurrentSkipListSet(SortedSet<E> s) {
124 m = new ConcurrentSkipListMap<E,Object>(s.comparator());
125 addAll(s);
126 }
127
128 /**
129 * For use by submaps
130 */
131 ConcurrentSkipListSet(ConcurrentNavigableMap<E,Object> m) {
132 this.m = m;
133 }
134
135 /**
136 * Returns a shallow copy of this {@code ConcurrentSkipListSet}
137 * instance. (The elements themselves are not cloned.)
138 *
139 * @return a shallow copy of this set
140 */
141 public ConcurrentSkipListSet<E> clone() {
142 try {
143 @SuppressWarnings("unchecked")
144 ConcurrentSkipListSet<E> clone =
145 (ConcurrentSkipListSet<E>) super.clone();
146 clone.setMap(new ConcurrentSkipListMap<E,Object>(m));
147 return clone;
148 } catch (CloneNotSupportedException e) {
149 throw new InternalError();
150 }
151 }
152
153 /* ---------------- Set operations -------------- */
154
155 /**
156 * Returns the number of elements in this set. If this set
157 * contains more than {@code Integer.MAX_VALUE} elements, it
158 * returns {@code Integer.MAX_VALUE}.
159 *
160 * <p>Beware that, unlike in most collections, this method is
161 * <em>NOT</em> a constant-time operation. Because of the
162 * asynchronous nature of these sets, determining the current
163 * number of elements requires traversing them all to count them.
164 * Additionally, it is possible for the size to change during
165 * execution of this method, in which case the returned result
166 * will be inaccurate. Thus, this method is typically not very
167 * useful in concurrent applications.
168 *
169 * @return the number of elements in this set
170 */
171 public int size() {
172 return m.size();
173 }
174
175 /**
176 * Returns {@code true} if this set contains no elements.
177 * @return {@code true} if this set contains no elements
178 */
179 public boolean isEmpty() {
180 return m.isEmpty();
181 }
182
183 /**
184 * Returns {@code true} if this set contains the specified element.
185 * More formally, returns {@code true} if and only if this set
186 * contains an element {@code e} such that {@code o.equals(e)}.
187 *
188 * @param o object to be checked for containment in this set
189 * @return {@code true} if this set contains the specified element
190 * @throws ClassCastException if the specified element cannot be
191 * compared with the elements currently in this set
192 * @throws NullPointerException if the specified element is null
193 */
194 public boolean contains(Object o) {
195 return m.containsKey(o);
196 }
197
198 /**
199 * Adds the specified element to this set if it is not already present.
200 * More formally, adds the specified element {@code e} to this set if
201 * the set contains no element {@code e2} such that {@code e.equals(e2)}.
202 * If this set already contains the element, the call leaves the set
203 * unchanged and returns {@code false}.
204 *
205 * @param e element to be added to this set
206 * @return {@code true} if this set did not already contain the
207 * specified element
208 * @throws ClassCastException if {@code e} cannot be compared
209 * with the elements currently in this set
210 * @throws NullPointerException if the specified element is null
211 */
212 public boolean add(E e) {
213 return m.putIfAbsent(e, Boolean.TRUE) == null;
214 }
215
216 /**
217 * Removes the specified element from this set if it is present.
218 * More formally, removes an element {@code e} such that
219 * {@code o.equals(e)}, if this set contains such an element.
220 * Returns {@code true} if this set contained the element (or
221 * equivalently, if this set changed as a result of the call).
222 * (This set will not contain the element once the call returns.)
223 *
224 * @param o object to be removed from this set, if present
225 * @return {@code true} if this set contained the specified element
226 * @throws ClassCastException if {@code o} cannot be compared
227 * with the elements currently in this set
228 * @throws NullPointerException if the specified element is null
229 */
230 public boolean remove(Object o) {
231 return m.remove(o, Boolean.TRUE);
232 }
233
234 /**
235 * Removes all of the elements from this set.
236 */
237 public void clear() {
238 m.clear();
239 }
240
241 /**
242 * Returns an iterator over the elements in this set in ascending order.
243 *
244 * @return an iterator over the elements in this set in ascending order
245 */
246 public Iterator<E> iterator() {
247 return m.navigableKeySet().iterator();
248 }
249
250 /**
251 * Returns an iterator over the elements in this set in descending order.
252 *
253 * @return an iterator over the elements in this set in descending order
254 */
255 public Iterator<E> descendingIterator() {
256 return m.descendingKeySet().iterator();
257 }
258
259
260 /* ---------------- AbstractSet Overrides -------------- */
261
262 /**
263 * Compares the specified object with this set for equality. Returns
264 * {@code true} if the specified object is also a set, the two sets
265 * have the same size, and every member of the specified set is
266 * contained in this set (or equivalently, every member of this set is
267 * contained in the specified set). This definition ensures that the
268 * equals method works properly across different implementations of the
269 * set interface.
270 *
271 * @param o the object to be compared for equality with this set
272 * @return {@code true} if the specified object is equal to this set
273 */
274 public boolean equals(Object o) {
275 // Override AbstractSet version to avoid calling size()
276 if (o == this)
277 return true;
278 if (!(o instanceof Set))
279 return false;
280 Collection<?> c = (Collection<?>) o;
281 try {
282 return containsAll(c) && c.containsAll(this);
283 } catch (ClassCastException | NullPointerException unused) {
284 return false;
285 }
286 }
287
288 /**
289 * Removes from this set all of its elements that are contained in
290 * the specified collection. If the specified collection is also
291 * a set, this operation effectively modifies this set so that its
292 * value is the <i>asymmetric set difference</i> of the two sets.
293 *
294 * @param c collection containing elements to be removed from this set
295 * @return {@code true} if this set changed as a result of the call
296 * @throws ClassCastException if the class of an element of this set
297 * is incompatible with the specified collection
298 * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
299 * @throws NullPointerException if the specified collection or any
300 * of its elements are null
301 */
302 public boolean removeAll(Collection<?> c) {
303 // Override AbstractSet version to avoid unnecessary call to size()
304 boolean modified = false;
305 for (Object e : c)
306 if (remove(e))
307 modified = true;
308 return modified;
309 }
310
311 /* ---------------- Relational operations -------------- */
312
313 /**
314 * @throws ClassCastException {@inheritDoc}
315 * @throws NullPointerException if the specified element is null
316 */
317 public E lower(E e) {
318 return m.lowerKey(e);
319 }
320
321 /**
322 * @throws ClassCastException {@inheritDoc}
323 * @throws NullPointerException if the specified element is null
324 */
325 public E floor(E e) {
326 return m.floorKey(e);
327 }
328
329 /**
330 * @throws ClassCastException {@inheritDoc}
331 * @throws NullPointerException if the specified element is null
332 */
333 public E ceiling(E e) {
334 return m.ceilingKey(e);
335 }
336
337 /**
338 * @throws ClassCastException {@inheritDoc}
339 * @throws NullPointerException if the specified element is null
340 */
341 public E higher(E e) {
342 return m.higherKey(e);
343 }
344
345 public E pollFirst() {
346 Map.Entry<E,Object> e = m.pollFirstEntry();
347 return (e == null) ? null : e.getKey();
348 }
349
350 public E pollLast() {
351 Map.Entry<E,Object> e = m.pollLastEntry();
352 return (e == null) ? null : e.getKey();
353 }
354
355
356 /* ---------------- SortedSet operations -------------- */
357
358 public Comparator<? super E> comparator() {
359 return m.comparator();
360 }
361
362 /**
363 * @throws java.util.NoSuchElementException {@inheritDoc}
364 */
365 public E first() {
366 return m.firstKey();
367 }
368
369 /**
370 * @throws java.util.NoSuchElementException {@inheritDoc}
371 */
372 public E last() {
373 return m.lastKey();
374 }
375
376 /**
377 * @throws ClassCastException {@inheritDoc}
378 * @throws NullPointerException if {@code fromElement} or
379 * {@code toElement} is null
380 * @throws IllegalArgumentException {@inheritDoc}
381 */
382 public NavigableSet<E> subSet(E fromElement,
383 boolean fromInclusive,
384 E toElement,
385 boolean toInclusive) {
386 return new ConcurrentSkipListSet<E>
387 (m.subMap(fromElement, fromInclusive,
388 toElement, toInclusive));
389 }
390
391 /**
392 * @throws ClassCastException {@inheritDoc}
393 * @throws NullPointerException if {@code toElement} is null
394 * @throws IllegalArgumentException {@inheritDoc}
395 */
396 public NavigableSet<E> headSet(E toElement, boolean inclusive) {
397 return new ConcurrentSkipListSet<E>(m.headMap(toElement, inclusive));
398 }
399
400 /**
401 * @throws ClassCastException {@inheritDoc}
402 * @throws NullPointerException if {@code fromElement} is null
403 * @throws IllegalArgumentException {@inheritDoc}
404 */
405 public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
406 return new ConcurrentSkipListSet<E>(m.tailMap(fromElement, inclusive));
407 }
408
409 /**
410 * @throws ClassCastException {@inheritDoc}
411 * @throws NullPointerException if {@code fromElement} or
412 * {@code toElement} is null
413 * @throws IllegalArgumentException {@inheritDoc}
414 */
415 public NavigableSet<E> subSet(E fromElement, E toElement) {
416 return subSet(fromElement, true, toElement, false);
417 }
418
419 /**
420 * @throws ClassCastException {@inheritDoc}
421 * @throws NullPointerException if {@code toElement} is null
422 * @throws IllegalArgumentException {@inheritDoc}
423 */
424 public NavigableSet<E> headSet(E toElement) {
425 return headSet(toElement, false);
426 }
427
428 /**
429 * @throws ClassCastException {@inheritDoc}
430 * @throws NullPointerException if {@code fromElement} is null
431 * @throws IllegalArgumentException {@inheritDoc}
432 */
433 public NavigableSet<E> tailSet(E fromElement) {
434 return tailSet(fromElement, true);
435 }
436
437 /**
438 * Returns a reverse order view of the elements contained in this set.
439 * The descending set is backed by this set, so changes to the set are
440 * reflected in the descending set, and vice-versa.
441 *
442 * <p>The returned set has an ordering equivalent to
443 * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
444 * The expression {@code s.descendingSet().descendingSet()} returns a
445 * view of {@code s} essentially equivalent to {@code s}.
446 *
447 * @return a reverse order view of this set
448 */
449 public NavigableSet<E> descendingSet() {
450 return new ConcurrentSkipListSet<E>(m.descendingMap());
451 }
452
453 /**
454 * Returns a {@link Spliterator} over the elements in this set.
455 *
456 * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
457 * {@link Spliterator#NONNULL}, {@link Spliterator#DISTINCT},
458 * {@link Spliterator#SORTED} and {@link Spliterator#ORDERED}, with an
459 * encounter order that is ascending order. Overriding implementations
460 * should document the reporting of additional characteristic values.
461 *
462 * <p>The {@linkplain Spliterator#getComparator() spliterator's comparator}
463 * is {@code null} if the {@linkplain #comparator() set's comparator}
464 * is {@code null}.
465 * Otherwise, the spliterator's comparator is the same as or imposes the
466 * same total ordering as the set's comparator.
467 *
468 * @return a {@code Spliterator} over the elements in this set
469 * @since 1.8
470 */
471 public Spliterator<E> spliterator() {
472 return (m instanceof ConcurrentSkipListMap)
473 ? ((ConcurrentSkipListMap<E,?>)m).keySpliterator()
474 : ((ConcurrentSkipListMap.SubMap<E,?>)m).new SubMapKeyIterator();
475 }
476
477 /** Initializes map field; for use in clone. */
478 private void setMap(ConcurrentNavigableMap<E,Object> map) {
479 Field mapField = java.security.AccessController.doPrivileged(
480 (java.security.PrivilegedAction<Field>) () -> {
481 try {
482 Field f = ConcurrentSkipListSet.class
483 .getDeclaredField("m");
484 f.setAccessible(true);
485 return f;
486 } catch (ReflectiveOperationException e) {
487 throw new Error(e);
488 }});
489 try {
490 mapField.set(this, map);
491 } catch (IllegalAccessException e) {
492 throw new Error(e);
493 }
494 }
495 }