ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/ConcurrentSkipListSet.java
Revision: 1.63
Committed: Fri Mar 18 16:01:41 2022 UTC (2 years, 2 months ago) by dl
Branch: MAIN
CVS Tags: HEAD
Changes since 1.62: +1 -0 lines
Log Message:
jdk17+ suppressWarnings, FJ updates

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 @SuppressWarnings("serial") // Conditionally serializable
78 private final ConcurrentNavigableMap<E,Object> m;
79
80 /**
81 * Constructs a new, empty set that orders its elements according to
82 * their {@linkplain Comparable natural ordering}.
83 */
84 public ConcurrentSkipListSet() {
85 m = new ConcurrentSkipListMap<E,Object>();
86 }
87
88 /**
89 * Constructs a new, empty set that orders its elements according to
90 * the specified comparator.
91 *
92 * @param comparator the comparator that will be used to order this set.
93 * If {@code null}, the {@linkplain Comparable natural
94 * ordering} of the elements will be used.
95 */
96 public ConcurrentSkipListSet(Comparator<? super E> comparator) {
97 m = new ConcurrentSkipListMap<E,Object>(comparator);
98 }
99
100 /**
101 * Constructs a new set containing the elements in the specified
102 * collection, that orders its elements according to their
103 * {@linkplain Comparable natural ordering}.
104 *
105 * @param c The elements that will comprise the new set
106 * @throws ClassCastException if the elements in {@code c} are
107 * not {@link Comparable}, or are not mutually comparable
108 * @throws NullPointerException if the specified collection or any
109 * of its elements are null
110 */
111 public ConcurrentSkipListSet(Collection<? extends E> c) {
112 m = new ConcurrentSkipListMap<E,Object>();
113 addAll(c);
114 }
115
116 /**
117 * Constructs a new set containing the same elements and using the
118 * same ordering as the specified sorted set.
119 *
120 * @param s sorted set whose elements will comprise the new set
121 * @throws NullPointerException if the specified sorted set or any
122 * of its elements are null
123 */
124 public ConcurrentSkipListSet(SortedSet<E> s) {
125 m = new ConcurrentSkipListMap<E,Object>(s.comparator());
126 addAll(s);
127 }
128
129 /**
130 * For use by submaps
131 */
132 ConcurrentSkipListSet(ConcurrentNavigableMap<E,Object> m) {
133 this.m = m;
134 }
135
136 /**
137 * Returns a shallow copy of this {@code ConcurrentSkipListSet}
138 * instance. (The elements themselves are not cloned.)
139 *
140 * @return a shallow copy of this set
141 */
142 public ConcurrentSkipListSet<E> clone() {
143 try {
144 @SuppressWarnings("unchecked")
145 ConcurrentSkipListSet<E> clone =
146 (ConcurrentSkipListSet<E>) super.clone();
147 clone.setMap(new ConcurrentSkipListMap<E,Object>(m));
148 return clone;
149 } catch (CloneNotSupportedException e) {
150 throw new InternalError();
151 }
152 }
153
154 /* ---------------- Set operations -------------- */
155
156 /**
157 * Returns the number of elements in this set. If this set
158 * contains more than {@code Integer.MAX_VALUE} elements, it
159 * returns {@code Integer.MAX_VALUE}.
160 *
161 * <p>Beware that, unlike in most collections, this method is
162 * <em>NOT</em> a constant-time operation. Because of the
163 * asynchronous nature of these sets, determining the current
164 * number of elements requires traversing them all to count them.
165 * Additionally, it is possible for the size to change during
166 * execution of this method, in which case the returned result
167 * will be inaccurate. Thus, this method is typically not very
168 * useful in concurrent applications.
169 *
170 * @return the number of elements in this set
171 */
172 public int size() {
173 return m.size();
174 }
175
176 /**
177 * Returns {@code true} if this set contains no elements.
178 * @return {@code true} if this set contains no elements
179 */
180 public boolean isEmpty() {
181 return m.isEmpty();
182 }
183
184 /**
185 * Returns {@code true} if this set contains the specified element.
186 * More formally, returns {@code true} if and only if this set
187 * contains an element {@code e} such that {@code o.equals(e)}.
188 *
189 * @param o object to be checked for containment in this set
190 * @return {@code true} if this set contains the specified element
191 * @throws ClassCastException if the specified element cannot be
192 * compared with the elements currently in this set
193 * @throws NullPointerException if the specified element is null
194 */
195 public boolean contains(Object o) {
196 return m.containsKey(o);
197 }
198
199 /**
200 * Adds the specified element to this set if it is not already present.
201 * More formally, adds the specified element {@code e} to this set if
202 * the set contains no element {@code e2} such that {@code e.equals(e2)}.
203 * If this set already contains the element, the call leaves the set
204 * unchanged and returns {@code false}.
205 *
206 * @param e element to be added to this set
207 * @return {@code true} if this set did not already contain the
208 * specified element
209 * @throws ClassCastException if {@code e} cannot be compared
210 * with the elements currently in this set
211 * @throws NullPointerException if the specified element is null
212 */
213 public boolean add(E e) {
214 return m.putIfAbsent(e, Boolean.TRUE) == null;
215 }
216
217 /**
218 * Removes the specified element from this set if it is present.
219 * More formally, removes an element {@code e} such that
220 * {@code o.equals(e)}, if this set contains such an element.
221 * Returns {@code true} if this set contained the element (or
222 * equivalently, if this set changed as a result of the call).
223 * (This set will not contain the element once the call returns.)
224 *
225 * @param o object to be removed from this set, if present
226 * @return {@code true} if this set contained the specified element
227 * @throws ClassCastException if {@code o} cannot be compared
228 * with the elements currently in this set
229 * @throws NullPointerException if the specified element is null
230 */
231 public boolean remove(Object o) {
232 return m.remove(o, Boolean.TRUE);
233 }
234
235 /**
236 * Removes all of the elements from this set.
237 */
238 public void clear() {
239 m.clear();
240 }
241
242 /**
243 * Returns an iterator over the elements in this set in ascending order.
244 *
245 * @return an iterator over the elements in this set in ascending order
246 */
247 public Iterator<E> iterator() {
248 return m.navigableKeySet().iterator();
249 }
250
251 /**
252 * Returns an iterator over the elements in this set in descending order.
253 *
254 * @return an iterator over the elements in this set in descending order
255 */
256 public Iterator<E> descendingIterator() {
257 return m.descendingKeySet().iterator();
258 }
259
260
261 /* ---------------- AbstractSet Overrides -------------- */
262
263 /**
264 * Compares the specified object with this set for equality. Returns
265 * {@code true} if the specified object is also a set, the two sets
266 * have the same size, and every member of the specified set is
267 * contained in this set (or equivalently, every member of this set is
268 * contained in the specified set). This definition ensures that the
269 * equals method works properly across different implementations of the
270 * set interface.
271 *
272 * @param o the object to be compared for equality with this set
273 * @return {@code true} if the specified object is equal to this set
274 */
275 public boolean equals(Object o) {
276 // Override AbstractSet version to avoid calling size()
277 if (o == this)
278 return true;
279 if (!(o instanceof Set))
280 return false;
281 Collection<?> c = (Collection<?>) o;
282 try {
283 return containsAll(c) && c.containsAll(this);
284 } catch (ClassCastException | NullPointerException unused) {
285 return false;
286 }
287 }
288
289 /**
290 * Removes from this set all of its elements that are contained in
291 * the specified collection. If the specified collection is also
292 * a set, this operation effectively modifies this set so that its
293 * value is the <i>asymmetric set difference</i> of the two sets.
294 *
295 * @param c collection containing elements to be removed from this set
296 * @return {@code true} if this set changed as a result of the call
297 * @throws ClassCastException if the class of an element of this set
298 * is incompatible with the specified collection
299 * (<a href="{@docRoot}/java.base/java/util/Collection.html#optional-restrictions">optional</a>)
300 * @throws NullPointerException if the specified collection or any
301 * of its elements are null
302 */
303 public boolean removeAll(Collection<?> c) {
304 // Override AbstractSet version to avoid unnecessary call to size()
305 boolean modified = false;
306 for (Object e : c)
307 if (remove(e))
308 modified = true;
309 return modified;
310 }
311
312 /* ---------------- Relational operations -------------- */
313
314 /**
315 * @throws ClassCastException {@inheritDoc}
316 * @throws NullPointerException if the specified element is null
317 */
318 public E lower(E e) {
319 return m.lowerKey(e);
320 }
321
322 /**
323 * @throws ClassCastException {@inheritDoc}
324 * @throws NullPointerException if the specified element is null
325 */
326 public E floor(E e) {
327 return m.floorKey(e);
328 }
329
330 /**
331 * @throws ClassCastException {@inheritDoc}
332 * @throws NullPointerException if the specified element is null
333 */
334 public E ceiling(E e) {
335 return m.ceilingKey(e);
336 }
337
338 /**
339 * @throws ClassCastException {@inheritDoc}
340 * @throws NullPointerException if the specified element is null
341 */
342 public E higher(E e) {
343 return m.higherKey(e);
344 }
345
346 public E pollFirst() {
347 Map.Entry<E,Object> e = m.pollFirstEntry();
348 return (e == null) ? null : e.getKey();
349 }
350
351 public E pollLast() {
352 Map.Entry<E,Object> e = m.pollLastEntry();
353 return (e == null) ? null : e.getKey();
354 }
355
356
357 /* ---------------- SortedSet operations -------------- */
358
359 public Comparator<? super E> comparator() {
360 return m.comparator();
361 }
362
363 /**
364 * @throws java.util.NoSuchElementException {@inheritDoc}
365 */
366 public E first() {
367 return m.firstKey();
368 }
369
370 /**
371 * @throws java.util.NoSuchElementException {@inheritDoc}
372 */
373 public E last() {
374 return m.lastKey();
375 }
376
377 /**
378 * @throws ClassCastException {@inheritDoc}
379 * @throws NullPointerException if {@code fromElement} or
380 * {@code toElement} is null
381 * @throws IllegalArgumentException {@inheritDoc}
382 */
383 public NavigableSet<E> subSet(E fromElement,
384 boolean fromInclusive,
385 E toElement,
386 boolean toInclusive) {
387 return new ConcurrentSkipListSet<E>
388 (m.subMap(fromElement, fromInclusive,
389 toElement, toInclusive));
390 }
391
392 /**
393 * @throws ClassCastException {@inheritDoc}
394 * @throws NullPointerException if {@code toElement} is null
395 * @throws IllegalArgumentException {@inheritDoc}
396 */
397 public NavigableSet<E> headSet(E toElement, boolean inclusive) {
398 return new ConcurrentSkipListSet<E>(m.headMap(toElement, inclusive));
399 }
400
401 /**
402 * @throws ClassCastException {@inheritDoc}
403 * @throws NullPointerException if {@code fromElement} is null
404 * @throws IllegalArgumentException {@inheritDoc}
405 */
406 public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
407 return new ConcurrentSkipListSet<E>(m.tailMap(fromElement, inclusive));
408 }
409
410 /**
411 * @throws ClassCastException {@inheritDoc}
412 * @throws NullPointerException if {@code fromElement} or
413 * {@code toElement} is null
414 * @throws IllegalArgumentException {@inheritDoc}
415 */
416 public NavigableSet<E> subSet(E fromElement, E toElement) {
417 return subSet(fromElement, true, toElement, false);
418 }
419
420 /**
421 * @throws ClassCastException {@inheritDoc}
422 * @throws NullPointerException if {@code toElement} is null
423 * @throws IllegalArgumentException {@inheritDoc}
424 */
425 public NavigableSet<E> headSet(E toElement) {
426 return headSet(toElement, false);
427 }
428
429 /**
430 * @throws ClassCastException {@inheritDoc}
431 * @throws NullPointerException if {@code fromElement} is null
432 * @throws IllegalArgumentException {@inheritDoc}
433 */
434 public NavigableSet<E> tailSet(E fromElement) {
435 return tailSet(fromElement, true);
436 }
437
438 /**
439 * Returns a reverse order view of the elements contained in this set.
440 * The descending set is backed by this set, so changes to the set are
441 * reflected in the descending set, and vice-versa.
442 *
443 * <p>The returned set has an ordering equivalent to
444 * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
445 * The expression {@code s.descendingSet().descendingSet()} returns a
446 * view of {@code s} essentially equivalent to {@code s}.
447 *
448 * @return a reverse order view of this set
449 */
450 public NavigableSet<E> descendingSet() {
451 return new ConcurrentSkipListSet<E>(m.descendingMap());
452 }
453
454 /**
455 * Returns a {@link Spliterator} over the elements in this set.
456 *
457 * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
458 * {@link Spliterator#NONNULL}, {@link Spliterator#DISTINCT},
459 * {@link Spliterator#SORTED} and {@link Spliterator#ORDERED}, with an
460 * encounter order that is ascending order. Overriding implementations
461 * should document the reporting of additional characteristic values.
462 *
463 * <p>The {@linkplain Spliterator#getComparator() spliterator's comparator}
464 * is {@code null} if the {@linkplain #comparator() set's comparator}
465 * is {@code null}.
466 * Otherwise, the spliterator's comparator is the same as or imposes the
467 * same total ordering as the set's comparator.
468 *
469 * @return a {@code Spliterator} over the elements in this set
470 * @since 1.8
471 */
472 public Spliterator<E> spliterator() {
473 return (m instanceof ConcurrentSkipListMap)
474 ? ((ConcurrentSkipListMap<E,?>)m).keySpliterator()
475 : ((ConcurrentSkipListMap.SubMap<E,?>)m).new SubMapKeyIterator();
476 }
477
478 /** Initializes map field; for use in clone. */
479 private void setMap(ConcurrentNavigableMap<E,Object> map) {
480 @SuppressWarnings({"deprecation", "removal"})
481 Field mapField = java.security.AccessController.doPrivileged(
482 (java.security.PrivilegedAction<Field>) () -> {
483 try {
484 Field f = ConcurrentSkipListSet.class
485 .getDeclaredField("m");
486 f.setAccessible(true);
487 return f;
488 } catch (ReflectiveOperationException e) {
489 throw new Error(e);
490 }});
491 try {
492 mapField.set(this, map);
493 } catch (IllegalAccessException e) {
494 throw new Error(e);
495 }
496 }
497 }