ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jdk7/java/util/concurrent/ConcurrentSkipListSet.java
Revision: 1.5
Committed: Sun Jan 18 20:17:32 2015 UTC (9 years, 3 months ago) by jsr166
Branch: MAIN
CVS Tags: HEAD
Changes since 1.4: +1 -0 lines
Log Message:
exactly one blank line before and after package statements

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