2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation. Oracle designates this
7 * particular file as subject to the "Classpath" exception as provided
8 * by Oracle in the LICENSE file that accompanied this code.
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
26 * This file is available under and governed by the GNU General Public
27 * License version 2 only, as published by the Free Software Foundation.
28 * However, the following notice accompanied the original version of this
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/
36 package java.util.concurrent;
40 * A scalable concurrent {@link NavigableSet} implementation based on
41 * a {@link ConcurrentSkipListMap}. The elements of the set are kept
42 * sorted according to their {@linkplain Comparable natural ordering},
43 * or by a {@link Comparator} provided at set creation time, depending
44 * on which constructor is used.
46 * <p>This implementation provides expected average <i>log(n)</i> time
47 * cost for the <tt>contains</tt>, <tt>add</tt>, and <tt>remove</tt>
48 * operations and their variants. Insertion, removal, and access
49 * operations safely execute concurrently by multiple threads.
50 * Iterators are <i>weakly consistent</i>, returning elements
51 * reflecting the state of the set at some point at or since the
52 * creation of the iterator. They do <em>not</em> throw {@link
53 * ConcurrentModificationException}, and may proceed concurrently with
54 * other operations. Ascending ordered views and their iterators are
55 * faster than descending ones.
57 * <p>Beware that, unlike in most collections, the <tt>size</tt>
58 * method is <em>not</em> a constant-time operation. Because of the
59 * asynchronous nature of these sets, determining the current number
60 * of elements requires a traversal of the elements, and so may report
61 * inaccurate results if this collection is modified during traversal.
62 * Additionally, the bulk operations <tt>addAll</tt>,
63 * <tt>removeAll</tt>, <tt>retainAll</tt>, <tt>containsAll</tt>,
64 * <tt>equals</tt>, and <tt>toArray</tt> are <em>not</em> guaranteed
65 * to be performed atomically. For example, an iterator operating
66 * concurrently with an <tt>addAll</tt> operation might view only some
67 * of the added elements.
69 * <p>This class and its iterators implement all of the
70 * <em>optional</em> methods of the {@link Set} and {@link Iterator}
71 * interfaces. Like most other concurrent collection implementations,
72 * this class does not permit the use of <tt>null</tt> elements,
73 * because <tt>null</tt> arguments and return values cannot be reliably
74 * distinguished from the absence of elements.
76 * <p>This class is a member of the
77 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
78 * Java Collections Framework</a>.
81 * @param <E> the type of elements maintained by this set
84 public class ConcurrentSkipListSet<E>
85 extends AbstractSet<E>
86 implements NavigableSet<E>, Cloneable, java.io.Serializable {
88 private static final long serialVersionUID = -2479143111061671589L;
91 * The underlying map. Uses Boolean.TRUE as value for each
92 * element. This field is declared final for the sake of thread
93 * safety, which entails some ugliness in clone()
95 private ConcurrentNavigableMap<E,Object> m;
98 * Constructs a new, empty set that orders its elements according to
99 * their {@linkplain Comparable natural ordering}.
101 public ConcurrentSkipListSet() {
102 m = new ConcurrentSkipListMap<E,Object>();
106 * Constructs a new, empty set that orders its elements according to
107 * the specified comparator.
109 * @param comparator the comparator that will be used to order this set.
110 * If <tt>null</tt>, the {@linkplain Comparable natural
111 * ordering} of the elements will be used.
113 public ConcurrentSkipListSet(Comparator<? super E> comparator) {
114 m = new ConcurrentSkipListMap<E,Object>(comparator);
118 * Constructs a new set containing the elements in the specified
119 * collection, that orders its elements according to their
120 * {@linkplain Comparable natural ordering}.
122 * @param c The elements that will comprise the new set
123 * @throws ClassCastException if the elements in <tt>c</tt> are
124 * not {@link Comparable}, or are not mutually comparable
125 * @throws NullPointerException if the specified collection or any
126 * of its elements are null
128 public ConcurrentSkipListSet(Collection<? extends E> c) {
129 m = new ConcurrentSkipListMap<E,Object>();
134 * Constructs a new set containing the same elements and using the
135 * same ordering as the specified sorted set.
137 * @param s sorted set whose elements will comprise the new set
138 * @throws NullPointerException if the specified sorted set or any
139 * of its elements are null
141 public ConcurrentSkipListSet(SortedSet<E> s) {
142 m = new ConcurrentSkipListMap<E,Object>(s.comparator());
149 ConcurrentSkipListSet(ConcurrentNavigableMap<E,Object> m) {
154 * Returns a shallow copy of this <tt>ConcurrentSkipListSet</tt>
155 * instance. (The elements themselves are not cloned.)
157 * @return a shallow copy of this set
159 public ConcurrentSkipListSet<E> clone() {
160 ConcurrentSkipListSet<E> clone = null;
162 clone = (ConcurrentSkipListSet<E>) super.clone();
163 clone.setMap(new ConcurrentSkipListMap(m));
164 } catch (CloneNotSupportedException e) {
165 throw new InternalError();
171 /* ---------------- Set operations -------------- */
174 * Returns the number of elements in this set. If this set
175 * contains more than <tt>Integer.MAX_VALUE</tt> elements, it
176 * returns <tt>Integer.MAX_VALUE</tt>.
178 * <p>Beware that, unlike in most collections, this method is
179 * <em>NOT</em> a constant-time operation. Because of the
180 * asynchronous nature of these sets, determining the current
181 * number of elements requires traversing them all to count them.
182 * Additionally, it is possible for the size to change during
183 * execution of this method, in which case the returned result
184 * will be inaccurate. Thus, this method is typically not very
185 * useful in concurrent applications.
187 * @return the number of elements in this set
194 * Returns <tt>true</tt> if this set contains no elements.
195 * @return <tt>true</tt> if this set contains no elements
197 public boolean isEmpty() {
202 * Returns <tt>true</tt> if this set contains the specified element.
203 * More formally, returns <tt>true</tt> if and only if this set
204 * contains an element <tt>e</tt> such that <tt>o.equals(e)</tt>.
206 * @param o object to be checked for containment in this set
207 * @return <tt>true</tt> if this set contains the specified element
208 * @throws ClassCastException if the specified element cannot be
209 * compared with the elements currently in this set
210 * @throws NullPointerException if the specified element is null
212 public boolean contains(Object o) {
213 return m.containsKey(o);
217 * Adds the specified element to this set if it is not already present.
218 * More formally, adds the specified element <tt>e</tt> to this set if
219 * the set contains no element <tt>e2</tt> such that <tt>e.equals(e2)</tt>.
220 * If this set already contains the element, the call leaves the set
221 * unchanged and returns <tt>false</tt>.
223 * @param e element to be added to this set
224 * @return <tt>true</tt> if this set did not already contain the
226 * @throws ClassCastException if <tt>e</tt> cannot be compared
227 * with the elements currently in this set
228 * @throws NullPointerException if the specified element is null
230 public boolean add(E e) {
231 return m.putIfAbsent(e, Boolean.TRUE) == null;
235 * Removes the specified element from this set if it is present.
236 * More formally, removes an element <tt>e</tt> such that
237 * <tt>o.equals(e)</tt>, if this set contains such an element.
238 * Returns <tt>true</tt> if this set contained the element (or
239 * equivalently, if this set changed as a result of the call).
240 * (This set will not contain the element once the call returns.)
242 * @param o object to be removed from this set, if present
243 * @return <tt>true</tt> if this set contained the specified element
244 * @throws ClassCastException if <tt>o</tt> cannot be compared
245 * with the elements currently in this set
246 * @throws NullPointerException if the specified element is null
248 public boolean remove(Object o) {
249 return m.remove(o, Boolean.TRUE);
253 * Removes all of the elements from this set.
255 public void clear() {
260 * Returns an iterator over the elements in this set in ascending order.
262 * @return an iterator over the elements in this set in ascending order
264 public Iterator<E> iterator() {
265 return m.navigableKeySet().iterator();
269 * Returns an iterator over the elements in this set in descending order.
271 * @return an iterator over the elements in this set in descending order
273 public Iterator<E> descendingIterator() {
274 return m.descendingKeySet().iterator();
278 /* ---------------- AbstractSet Overrides -------------- */
281 * Compares the specified object with this set for equality. Returns
282 * <tt>true</tt> if the specified object is also a set, the two sets
283 * have the same size, and every member of the specified set is
284 * contained in this set (or equivalently, every member of this set is
285 * contained in the specified set). This definition ensures that the
286 * equals method works properly across different implementations of the
289 * @param o the object to be compared for equality with this set
290 * @return <tt>true</tt> if the specified object is equal to this set
292 public boolean equals(Object o) {
293 // Override AbstractSet version to avoid calling size()
296 if (!(o instanceof Set))
298 Collection<?> c = (Collection<?>) o;
300 return containsAll(c) && c.containsAll(this);
301 } catch (ClassCastException unused) {
303 } catch (NullPointerException unused) {
309 * Removes from this set all of its elements that are contained in
310 * the specified collection. If the specified collection is also
311 * a set, this operation effectively modifies this set so that its
312 * value is the <i>asymmetric set difference</i> of the two sets.
314 * @param c collection containing elements to be removed from this set
315 * @return <tt>true</tt> if this set changed as a result of the call
316 * @throws ClassCastException if the types of one or more elements in this
317 * set are incompatible with the specified collection
318 * @throws NullPointerException if the specified collection or any
319 * of its elements are null
321 public boolean removeAll(Collection<?> c) {
322 // Override AbstractSet version to avoid unnecessary call to size()
323 boolean modified = false;
324 for (Iterator<?> i = c.iterator(); i.hasNext(); )
325 if (remove(i.next()))
330 /* ---------------- Relational operations -------------- */
333 * @throws ClassCastException {@inheritDoc}
334 * @throws NullPointerException if the specified element is null
336 public E lower(E e) {
337 return m.lowerKey(e);
341 * @throws ClassCastException {@inheritDoc}
342 * @throws NullPointerException if the specified element is null
344 public E floor(E e) {
345 return m.floorKey(e);
349 * @throws ClassCastException {@inheritDoc}
350 * @throws NullPointerException if the specified element is null
352 public E ceiling(E e) {
353 return m.ceilingKey(e);
357 * @throws ClassCastException {@inheritDoc}
358 * @throws NullPointerException if the specified element is null
360 public E higher(E e) {
361 return m.higherKey(e);
364 public E pollFirst() {
365 Map.Entry<E,Object> e = m.pollFirstEntry();
366 return (e == null) ? null : e.getKey();
369 public E pollLast() {
370 Map.Entry<E,Object> e = m.pollLastEntry();
371 return (e == null) ? null : e.getKey();
375 /* ---------------- SortedSet operations -------------- */
378 public Comparator<? super E> comparator() {
379 return m.comparator();
383 * @throws NoSuchElementException {@inheritDoc}
390 * @throws NoSuchElementException {@inheritDoc}
397 * @throws ClassCastException {@inheritDoc}
398 * @throws NullPointerException if {@code fromElement} or
399 * {@code toElement} is null
400 * @throws IllegalArgumentException {@inheritDoc}
402 public NavigableSet<E> subSet(E fromElement,
403 boolean fromInclusive,
405 boolean toInclusive) {
406 return new ConcurrentSkipListSet<E>
407 (m.subMap(fromElement, fromInclusive,
408 toElement, toInclusive));
412 * @throws ClassCastException {@inheritDoc}
413 * @throws NullPointerException if {@code toElement} is null
414 * @throws IllegalArgumentException {@inheritDoc}
416 public NavigableSet<E> headSet(E toElement, boolean inclusive) {
417 return new ConcurrentSkipListSet<E>(m.headMap(toElement, inclusive));
421 * @throws ClassCastException {@inheritDoc}
422 * @throws NullPointerException if {@code fromElement} is null
423 * @throws IllegalArgumentException {@inheritDoc}
425 public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
426 return new ConcurrentSkipListSet<E>(m.tailMap(fromElement, inclusive));
430 * @throws ClassCastException {@inheritDoc}
431 * @throws NullPointerException if {@code fromElement} or
432 * {@code toElement} is null
433 * @throws IllegalArgumentException {@inheritDoc}
435 public NavigableSet<E> subSet(E fromElement, E toElement) {
436 return subSet(fromElement, true, toElement, false);
440 * @throws ClassCastException {@inheritDoc}
441 * @throws NullPointerException if {@code toElement} is null
442 * @throws IllegalArgumentException {@inheritDoc}
444 public NavigableSet<E> headSet(E toElement) {
445 return headSet(toElement, false);
449 * @throws ClassCastException {@inheritDoc}
450 * @throws NullPointerException if {@code fromElement} is null
451 * @throws IllegalArgumentException {@inheritDoc}
453 public NavigableSet<E> tailSet(E fromElement) {
454 return tailSet(fromElement, true);
458 * Returns a reverse order view of the elements contained in this set.
459 * The descending set is backed by this set, so changes to the set are
460 * reflected in the descending set, and vice-versa.
462 * <p>The returned set has an ordering equivalent to
463 * <tt>{@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator())</tt>.
464 * The expression {@code s.descendingSet().descendingSet()} returns a
465 * view of {@code s} essentially equivalent to {@code s}.
467 * @return a reverse order view of this set
469 public NavigableSet<E> descendingSet() {
470 return new ConcurrentSkipListSet(m.descendingMap());
473 // Support for resetting map in clone
474 private void setMap(ConcurrentNavigableMap<E,Object> map) {