ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/ConcurrentSkipListSet.java
Revision: 1.5
Committed: Mon May 2 08:35:49 2005 UTC (19 years, 1 month ago) by jsr166
Branch: MAIN
Changes since 1.4: +29 -29 lines
Log Message:
E o -> E e

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/licenses/publicdomain
5 */
6
7 package java.util.concurrent;
8 import java.util.*;
9
10 /**
11 * A scalable concurrent {@link NavigableSet} implementation based on
12 * a {@link ConcurrentSkipListMap}. This class maintains a set in
13 * ascending order, sorted according to the <i>natural order</i> for
14 * the elements' class (see {@link Comparable}), or by the comparator
15 * provided at creation time, depending on which constructor is
16 * used.<p>
17 *
18 * This implementation provides expected average <i>log(n)</i> time
19 * cost for the <tt>contains</tt>, <tt>add</tt>, and <tt>remove</tt>
20 * operations and their variants. Insertion, removal, and access
21 * operations safely execute concurrently by multiple
22 * threads. 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.
27 *
28 * <p>Beware that, unlike in most collections, the <tt>size</tt>
29 * method is <em>not</em> a constant-time operation. Because of the
30 * asynchronous nature of these sets, determining the current number
31 * of elements requires a traversal of the elements. Additionally, the
32 * bulk operations <tt>addAll</tt>, <tt>removeAll</tt>,
33 * <tt>retainAll</tt>, and <tt>containsAll</tt> are <em>not</em>
34 * guaranteed to be performed atomically. For example, an iterator
35 * operating concurrently with an <tt>addAll</tt> operation might view
36 * only some of the added elements.
37 *
38 * <p>This class and its iterators implement all of the
39 * <em>optional</em> methods of the {@link Set} and {@link Iterator}
40 * interfaces. Like most other concurrent collection implementations,
41 * this class does not permit the use of <tt>null</tt> elements.
42 * because <tt>null</tt> arguments and return values cannot be reliably
43 * distinguished from the absence of elements.
44 *
45 * @author Doug Lea
46 * @param <E> the type of elements maintained by this set
47 */
48 public class ConcurrentSkipListSet<E>
49 extends AbstractSet<E>
50 implements NavigableSet<E>, Cloneable, java.io.Serializable {
51
52 private static final long serialVersionUID = -2479143111061671589L;
53
54 /**
55 * The underlying map. Uses Boolean.TRUE as value for each
56 * element. Note that this class relies on default serialization,
57 * which is a little wasteful in saving all of the useless value
58 * fields of underlying map, but enables this field to be declared
59 * final, which is necessary for thread safety.
60 */
61 private final ConcurrentSkipListMap<E,Object> m;
62
63 /**
64 * Constructs a new, empty set, sorted according to the elements' natural
65 * order.
66 */
67 public ConcurrentSkipListSet() {
68 m = new ConcurrentSkipListMap<E,Object>();
69 }
70
71 /**
72 * Constructs a new, empty set, sorted according to the specified
73 * comparator.
74 *
75 * @param c the comparator that will be used to sort this set. A
76 * <tt>null</tt> value indicates that the elements' <i>natural
77 * ordering</i> should be used.
78 */
79 public ConcurrentSkipListSet(Comparator<? super E> c) {
80 m = new ConcurrentSkipListMap<E,Object>(c);
81 }
82
83 /**
84 * Constructs a new set containing the elements in the specified
85 * collection, sorted according to the elements' <i>natural order</i>.
86 *
87 * @param c The elements that will comprise the new set.
88 *
89 * @throws ClassCastException if the elements in the specified
90 * collection are not comparable, or are not mutually comparable.
91 * @throws NullPointerException if the specified collection is
92 * <tt>null</tt>.
93 */
94 public ConcurrentSkipListSet(Collection<? extends E> c) {
95 m = new ConcurrentSkipListMap<E,Object>();
96 addAll(c);
97 }
98
99 /**
100 * Constructs a new set containing the same elements as the specified
101 * sorted set, sorted according to the same ordering.
102 *
103 * @param s sorted set whose elements will comprise the new set.
104 * @throws NullPointerException if the specified sorted set is
105 * <tt>null</tt>.
106 */
107 public ConcurrentSkipListSet(SortedSet<E> s) {
108 m = new ConcurrentSkipListMap<E,Object>(s.comparator());
109 addAll(s);
110 }
111
112 /**
113 * Returns a shallow copy of this set. (The elements themselves
114 * are not cloned.)
115 *
116 * @return a shallow copy of this set.
117 */
118 public Object clone() {
119 ConcurrentSkipListSet<E> clone = null;
120 try {
121 clone = (ConcurrentSkipListSet<E>) super.clone();
122 } catch (CloneNotSupportedException e) {
123 throw new InternalError();
124 }
125
126 clone.m.initialize();
127 clone.addAll(this);
128 return clone;
129 }
130
131 /* ---------------- Set operations -------------- */
132
133 /**
134 * Returns the number of elements in this set. If this set
135 * contains more than <tt>Integer.MAX_VALUE</tt> elements, it
136 * returns <tt>Integer.MAX_VALUE</tt>.
137 *
138 * <p>Beware that, unlike in most collections, this method is
139 * <em>NOT</em> a constant-time operation. Because of the
140 * asynchronous nature of these sets, determining the current
141 * number of elements requires traversing them all to count them.
142 * Additionally, it is possible for the size to change during
143 * execution of this method, in which case the returned result
144 * will be inaccurate. Thus, this method is typically not very
145 * useful in concurrent applications.
146 *
147 * @return the number of elements in this set.
148 */
149 public int size() {
150 return m.size();
151 }
152
153 /**
154 * Returns <tt>true</tt> if this set contains no elements.
155 * @return <tt>true</tt> if this set contains no elements.
156 */
157 public boolean isEmpty() {
158 return m.isEmpty();
159 }
160
161 /**
162 * Returns <tt>true</tt> if this set contains the specified element.
163 *
164 * @param o the object to be checked for containment in this set.
165 * @return <tt>true</tt> if this set contains the specified element.
166 *
167 * @throws ClassCastException if the specified object cannot be compared
168 * with the elements currently in the set.
169 * @throws NullPointerException if o is <tt>null</tt>.
170 */
171 public boolean contains(Object o) {
172 return m.containsKey(o);
173 }
174
175 /**
176 * Adds the specified element to this set if it is not already present.
177 *
178 * @param e element to be added to this set.
179 * @return <tt>true</tt> if the set did not already contain the specified
180 * element.
181 *
182 * @throws ClassCastException if the specified object cannot be compared
183 * with the elements currently in the set.
184 * @throws NullPointerException if e is <tt>null</tt>.
185 */
186 public boolean add(E e) {
187 return m.putIfAbsent(e, Boolean.TRUE) == null;
188 }
189
190 /**
191 * Removes the specified element from this set if it is present.
192 *
193 * @param o object to be removed from this set, if present.
194 * @return <tt>true</tt> if the set contained the specified element.
195 *
196 * @throws ClassCastException if the specified object cannot be compared
197 * with the elements currently in the set.
198 * @throws NullPointerException if o is <tt>null</tt>.
199 */
200 public boolean remove(Object o) {
201 return m.removep(o);
202 }
203
204 /**
205 * Removes all of the elements from this set.
206 */
207 public void clear() {
208 m.clear();
209 }
210
211 /**
212 * Returns an iterator over the elements in this set. The elements
213 * are returned in ascending order.
214 *
215 * @return an iterator over the elements in this set.
216 */
217 public Iterator<E> iterator() {
218 return m.keyIterator();
219 }
220
221 /**
222 * Returns an iterator over the elements in this set. The elements
223 * are returned in descending order.
224 *
225 * @return an iterator over the elements in this set.
226 */
227 public Iterator<E> descendingIterator() {
228 return m.descendingKeyIterator();
229 }
230
231 /* ---------------- AbstractSet Overrides -------------- */
232
233 /**
234 * Compares the specified object with this set for equality. Returns
235 * <tt>true</tt> if the specified object is also a set, the two sets
236 * have the same size, and every member of the specified set is
237 * contained in this set (or equivalently, every member of this set is
238 * contained in the specified set). This definition ensures that the
239 * equals method works properly across different implementations of the
240 * set interface.
241 *
242 * @param o Object to be compared for equality with this set.
243 * @return <tt>true</tt> if the specified Object is equal to this set.
244 */
245 public boolean equals(Object o) {
246 // Override AbstractSet version to avoid calling size()
247 if (o == this)
248 return true;
249 if (!(o instanceof Set))
250 return false;
251 Collection c = (Collection) o;
252 try {
253 return containsAll(c) && c.containsAll(this);
254 } catch(ClassCastException unused) {
255 return false;
256 } catch(NullPointerException unused) {
257 return false;
258 }
259 }
260
261 /**
262 * Removes from this set all of its elements that are contained in
263 * the specified collection. If the specified collection is also
264 * a set, this operation effectively modifies this set so that its
265 * value is the <i>asymmetric set difference</i> of the two sets.
266 *
267 * @param c collection that defines which elements will be removed from
268 * this set.
269 * @return <tt>true</tt> if this set changed as a result of the call.
270 *
271 * @throws ClassCastException if the types of one or more elements in this
272 * set are incompatible with the specified collection
273 * @throws NullPointerException if the specified collection, or any
274 * of its elements are <tt>null</tt>.
275 */
276 public boolean removeAll(Collection<?> c) {
277 // Override AbstractSet version to avoid unnecessary call to size()
278 boolean modified = false;
279 for (Iterator<?> i = c.iterator(); i.hasNext(); )
280 if (remove(i.next()))
281 modified = true;
282 return modified;
283 }
284
285 /* ---------------- Relational operations -------------- */
286
287 /**
288 * Returns an element greater than or equal to the given element, or
289 * <tt>null</tt> if there is no such element.
290 *
291 * @param e the value to match
292 * @return an element greater than or equal to given element, or
293 * <tt>null</tt> if there is no such element.
294 * @throws ClassCastException if e cannot be compared with the elements
295 * currently in the set.
296 * @throws NullPointerException if e is <tt>null</tt>
297 */
298 public E ceiling(E e) {
299 return m.ceilingKey(e);
300 }
301
302 /**
303 * Returns an element strictly less than the given element, or
304 * <tt>null</tt> if there is no such element.
305 *
306 * @param e the value to match
307 * @return the greatest element less than the given element, or
308 * <tt>null</tt> if there is no such element.
309 * @throws ClassCastException if e cannot be compared with the elements
310 * currently in the set.
311 * @throws NullPointerException if e is <tt>null</tt>.
312 */
313 public E lower(E e) {
314 return m.lowerKey(e);
315 }
316
317 /**
318 * Returns an element less than or equal to the given element, or
319 * <tt>null</tt> if there is no such element.
320 *
321 * @param e the value to match
322 * @return the greatest element less than or equal to given
323 * element, or <tt>null</tt> if there is no such element.
324 * @throws ClassCastException if e cannot be compared with the elements
325 * currently in the set.
326 * @throws NullPointerException if e is <tt>null</tt>.
327 */
328 public E floor(E e) {
329 return m.floorKey(e);
330 }
331
332 /**
333 * Returns an element strictly greater than the given element, or
334 * <tt>null</tt> if there is no such element.
335 *
336 * @param e the value to match
337 * @return the least element greater than the given element, or
338 * <tt>null</tt> if there is no such element.
339 * @throws ClassCastException if e cannot be compared with the elements
340 * currently in the set.
341 * @throws NullPointerException if e is <tt>null</tt>.
342 */
343 public E higher(E e) {
344 return m.higherKey(e);
345 }
346
347 /**
348 * Retrieves and removes the first (lowest) element.
349 *
350 * @return the least element, or <tt>null</tt> if empty.
351 */
352 public E pollFirst() {
353 return m.pollFirstKey();
354 }
355
356 /**
357 * Retrieves and removes the last (highest) element.
358 *
359 * @return the last element, or <tt>null</tt> if empty.
360 */
361 public E pollLast() {
362 return m.pollLastKey();
363 }
364
365
366 /* ---------------- SortedSet operations -------------- */
367
368
369 /**
370 * Returns the comparator used to order this set, or <tt>null</tt>
371 * if this set uses its elements natural ordering.
372 *
373 * @return the comparator used to order this set, or <tt>null</tt>
374 * if this set uses its elements natural ordering.
375 */
376 public Comparator<? super E> comparator() {
377 return m.comparator();
378 }
379
380 /**
381 * Returns the first (lowest) element currently in this set.
382 *
383 * @return the first (lowest) element currently in this set.
384 * @throws NoSuchElementException sorted set is empty.
385 */
386 public E first() {
387 return m.firstKey();
388 }
389
390 /**
391 * Returns the last (highest) element currently in this set.
392 *
393 * @return the last (highest) element currently in this set.
394 * @throws NoSuchElementException sorted set is empty.
395 */
396 public E last() {
397 return m.lastKey();
398 }
399
400 /**
401 * Returns a view of the portion of this set whose elements range from
402 * <tt>fromElement</tt>, inclusive, to <tt>toElement</tt>, exclusive. (If
403 * <tt>fromElement</tt> and <tt>toElement</tt> are equal, the returned
404 * navigable set is empty.) The returned navigable set is backed by this set,
405 * so changes in the returned navigable set are reflected in this set, and
406 * vice-versa.
407 * @param fromElement low endpoint (inclusive) of the subSet.
408 * @param toElement high endpoint (exclusive) of the subSet.
409 * @return a view of the portion of this set whose elements range from
410 * <tt>fromElement</tt>, inclusive, to <tt>toElement</tt>,
411 * exclusive.
412 * @throws ClassCastException if <tt>fromElement</tt> and
413 * <tt>toElement</tt> cannot be compared to one another using
414 * this set's comparator (or, if the set has no comparator,
415 * using natural ordering).
416 * @throws IllegalArgumentException if <tt>fromElement</tt> is
417 * greater than <tt>toElement</tt>.
418 * @throws NullPointerException if <tt>fromElement</tt> or
419 * <tt>toElement</tt> is <tt>null</tt>.
420 */
421 public NavigableSet<E> navigableSubSet(E fromElement, E toElement) {
422 return new ConcurrentSkipListSubSet<E>(m, fromElement, toElement);
423 }
424
425 /**
426 * Returns a view of the portion of this set whose elements are strictly
427 * less than <tt>toElement</tt>. The returned navigable set is backed by
428 * this set, so changes in the returned navigable set are reflected in this
429 * set, and vice-versa.
430 * @param toElement high endpoint (exclusive) of the headSet.
431 * @return a view of the portion of this set whose elements are strictly
432 * less than toElement.
433 * @throws ClassCastException if <tt>toElement</tt> is not compatible
434 * with this set's comparator (or, if the set has no comparator,
435 * if <tt>toElement</tt> does not implement <tt>Comparable</tt>).
436 * @throws NullPointerException if <tt>toElement</tt> is <tt>null</tt>.
437 */
438 public NavigableSet<E> navigableHeadSet(E toElement) {
439 return new ConcurrentSkipListSubSet<E>(m, null, toElement);
440 }
441
442
443 /**
444 * Returns a view of the portion of this set whose elements are
445 * greater than or equal to <tt>fromElement</tt>. The returned
446 * navigable set is backed by this set, so changes in the returned
447 * navigable set are reflected in this set, and vice-versa.
448 * @param fromElement low endpoint (inclusive) of the tailSet.
449 * @return a view of the portion of this set whose elements are
450 * greater than or equal to <tt>fromElement</tt>.
451 * @throws ClassCastException if <tt>fromElement</tt> is not
452 * compatible with this set's comparator (or, if the set has no
453 * comparator, if <tt>fromElement</tt> does not implement
454 * <tt>Comparable</tt>).
455 * @throws NullPointerException if <tt>fromElement</tt> is <tt>null</tt>.
456 */
457 public NavigableSet<E> navigableTailSet(E fromElement) {
458 return new ConcurrentSkipListSubSet<E>(m, fromElement, null);
459 }
460
461
462 /**
463 * Equivalent to <tt>navigableSubSet</tt> but with a return
464 * type conforming to the <tt>SortedSet</tt> interface.
465 * @param fromElement low endpoint (inclusive) of the subSet.
466 * @param toElement high endpoint (exclusive) of the subSet.
467 * @return a view of the portion of this set whose elements range from
468 * <tt>fromElement</tt>, inclusive, to <tt>toElement</tt>,
469 * exclusive.
470 * @throws ClassCastException if <tt>fromElement</tt> and
471 * <tt>toElement</tt> cannot be compared to one another using
472 * this set's comparator (or, if the set has no comparator,
473 * using natural ordering).
474 * @throws IllegalArgumentException if <tt>fromElement</tt> is
475 * greater than <tt>toElement</tt>.
476 * @throws NullPointerException if <tt>fromElement</tt> or
477 * <tt>toElement</tt> is <tt>null</tt>.
478 */
479 public SortedSet<E> subSet(E fromElement, E toElement) {
480 return navigableSubSet(fromElement, toElement);
481 }
482
483 /**
484 * Equivalent to <tt>navigableHeadSet</tt> but with a return
485 * type conforming to the <tt>SortedSet</tt> interface.
486 * @param toElement high endpoint (exclusive) of the headSet.
487 * @return a view of the portion of this set whose elements are strictly
488 * less than toElement.
489 * @throws ClassCastException if <tt>toElement</tt> is not compatible
490 * with this set's comparator (or, if the set has no comparator,
491 * if <tt>toElement</tt> does not implement <tt>Comparable</tt>).
492 * @throws NullPointerException if <tt>toElement</tt> is <tt>null</tt>.
493 */
494 public SortedSet<E> headSet(E toElement) {
495 return navigableHeadSet(toElement);
496 }
497
498
499 /**
500 * Equivalent to <tt>navigableTailSet</tt> but with a return
501 * type conforming to the <tt>SortedSet</tt> interface.
502 * @param fromElement low endpoint (inclusive) of the tailSet.
503 * @return a view of the portion of this set whose elements are
504 * greater than or equal to <tt>fromElement</tt>.
505 * @throws ClassCastException if <tt>fromElement</tt> is not
506 * compatible with this set's comparator (or, if the set has no
507 * comparator, if <tt>fromElement</tt> does not implement
508 * <tt>Comparable</tt>).
509 * @throws NullPointerException if <tt>fromElement</tt> is <tt>null</tt>.
510 */
511 public SortedSet<E> tailSet(E fromElement) {
512 return navigableTailSet(fromElement);
513 }
514
515 /**
516 * Subsets returned by {@link ConcurrentSkipListSet} subset operations
517 * represent a subrange of elements of their underlying
518 * sets. Instances of this class support all methods of their
519 * underlying sets, differing in that elements outside their range are
520 * ignored, and attempts to add elements outside their ranges result
521 * in {@link IllegalArgumentException}. Instances of this class are
522 * constructed only using the <tt>subSet</tt>, <tt>headSet</tt>, and
523 * <tt>tailSet</tt> methods of their underlying sets.
524 *
525 */
526 static class ConcurrentSkipListSubSet<E>
527 extends AbstractSet<E>
528 implements NavigableSet<E>, java.io.Serializable {
529
530 private static final long serialVersionUID = -7647078645896651609L;
531
532 /** The underlying submap */
533 private final ConcurrentSkipListMap.ConcurrentSkipListSubMap<E,Object> s;
534
535 /**
536 * Creates a new submap.
537 * @param fromElement inclusive least value, or <tt>null</tt> if from start
538 * @param toElement exclusive upper bound or <tt>null</tt> if to end
539 * @throws IllegalArgumentException if fromElement and toElement
540 * nonnull and fromElement greater than toElement
541 */
542 ConcurrentSkipListSubSet(ConcurrentSkipListMap<E,Object> map,
543 E fromElement, E toElement) {
544 s = new ConcurrentSkipListMap.ConcurrentSkipListSubMap<E,Object>
545 (map, fromElement, toElement);
546 }
547
548 // subsubset construction
549
550 public NavigableSet<E> navigableSubSet(E fromElement, E toElement) {
551 if (!s.inOpenRange(fromElement) || !s.inOpenRange(toElement))
552 throw new IllegalArgumentException("element out of range");
553 return new ConcurrentSkipListSubSet<E>(s.getMap(),
554 fromElement, toElement);
555 }
556
557 public NavigableSet<E> navigableHeadSet(E toElement) {
558 E least = s.getLeast();
559 if (!s.inOpenRange(toElement))
560 throw new IllegalArgumentException("element out of range");
561 return new ConcurrentSkipListSubSet<E>(s.getMap(),
562 least, toElement);
563 }
564
565 public NavigableSet<E> navigableTailSet(E fromElement) {
566 E fence = s.getFence();
567 if (!s.inOpenRange(fromElement))
568 throw new IllegalArgumentException("element out of range");
569 return new ConcurrentSkipListSubSet<E>(s.getMap(),
570 fromElement, fence);
571 }
572
573 public SortedSet<E> subSet(E fromElement, E toElement) {
574 return navigableSubSet(fromElement, toElement);
575 }
576
577 public SortedSet<E> headSet(E toElement) {
578 return navigableHeadSet(toElement);
579 }
580
581 public SortedSet<E> tailSet(E fromElement) {
582 return navigableTailSet(fromElement);
583 }
584
585 // relays to submap methods
586
587 public int size() { return s.size(); }
588 public boolean isEmpty() { return s.isEmpty(); }
589 public boolean contains(Object o) { return s.containsKey(o); }
590 public void clear() { s.clear(); }
591 public E first() { return s.firstKey(); }
592 public E last() { return s.lastKey(); }
593 public E ceiling(E e) { return s.ceilingKey(e); }
594 public E lower(E e) { return s.lowerKey(e); }
595 public E floor(E e) { return s.floorKey(e); }
596 public E higher(E e) { return s.higherKey(e); }
597 public boolean remove(Object o) { return s.remove(o)==Boolean.TRUE; }
598 public boolean add(E e) { return s.put(e, Boolean.TRUE)==null; }
599 public Comparator<? super E> comparator() { return s.comparator(); }
600 public Iterator<E> iterator() { return s.keySet().iterator(); }
601 public Iterator<E> descendingIterator() {
602 return s.descendingKeySet().iterator();
603 }
604 public E pollFirst() {
605 Map.Entry<E,?> e = s.pollFirstEntry();
606 return (e == null)? null : e.getKey();
607 }
608 public E pollLast() {
609 Map.Entry<E,?> e = s.pollLastEntry();
610 return (e == null)? null : e.getKey();
611 }
612
613 }
614 }