Java並發包--ConcurrentSkipListSet


轉載請注明出處:http://www.cnblogs.com/skywang12345/p/3498634.html

 

ConcurrentSkipListSet介紹

ConcurrentSkipListSet是線程安全的有序的集合,適用於高並發的場景。
ConcurrentSkipListSet和TreeSet,它們雖然都是有序的集合。但是,第一,它們的線程安全機制不同,TreeSet是非線程安全的,而ConcurrentSkipListSet是線程安全的。第二,ConcurrentSkipListSet是通過ConcurrentSkipListMap實現的,而TreeSet是通過TreeMap實現的。

 

ConcurrentSkipListSet原理和數據結構

ConcurrentSkipListSet的數據結構,如下圖所示:

說明
(01) ConcurrentSkipListSet繼承於AbstractSet。因此,它本質上是一個集合。
(02) ConcurrentSkipListSet實現了NavigableSet接口。因此,ConcurrentSkipListSet是一個有序的集合。
(03) ConcurrentSkipListSet是通過ConcurrentSkipListMap實現的。它包含一個ConcurrentNavigableMap對象m,而m對象實際上是ConcurrentNavigableMap的實現類ConcurrentSkipListMap的實例。ConcurrentSkipListMap中的元素是key-value鍵值對;而ConcurrentSkipListSet是集合,它只用到了ConcurrentSkipListMap中的key!

 

ConcurrentSkipListSet函數列表

復制代碼
// 構造一個新的空 set,該 set 按照元素的自然順序對其進行排序。
ConcurrentSkipListSet()
// 構造一個包含指定 collection 中元素的新 set,這個新 set 按照元素的自然順序對其進行排序。
ConcurrentSkipListSet(Collection<? extends E> c)
// 構造一個新的空 set,該 set 按照指定的比較器對其元素進行排序。
ConcurrentSkipListSet(Comparator<? super E> comparator)
// 構造一個新 set,該 set 所包含的元素與指定的有序 set 包含的元素相同,使用的順序也相同。
ConcurrentSkipListSet(SortedSet<E> s)

// 如果此 set 中不包含指定元素,則添加指定元素。
boolean add(E e)
// 返回此 set 中大於等於給定元素的最小元素;如果不存在這樣的元素,則返回 null。
E ceiling(E e)
// 從此 set 中移除所有元素。
void clear()
// 返回此 ConcurrentSkipListSet 實例的淺表副本。
ConcurrentSkipListSet<E> clone()
// 返回對此 set 中的元素進行排序的比較器;如果此 set 使用其元素的自然順序,則返回 null。
Comparator<? super E> comparator()
// 如果此 set 包含指定的元素,則返回 true。
boolean contains(Object o)
// 返回在此 set 的元素上以降序進行迭代的迭代器。
Iterator<E> descendingIterator()
// 返回此 set 中所包含元素的逆序視圖。
NavigableSet<E> descendingSet()
// 比較指定對象與此 set 的相等性。
boolean equals(Object o)
// 返回此 set 中當前第一個(最低)元素。
E first()
// 返回此 set 中小於等於給定元素的最大元素;如果不存在這樣的元素,則返回 null。
E floor(E e)
// 返回此 set 的部分視圖,其元素嚴格小於 toElement。
NavigableSet<E> headSet(E toElement)
// 返回此 set 的部分視圖,其元素小於(或等於,如果 inclusive 為 true)toElement。
NavigableSet<E> headSet(E toElement, boolean inclusive)
// 返回此 set 中嚴格大於給定元素的最小元素;如果不存在這樣的元素,則返回 null。
E higher(E e)
// 如果此 set 不包含任何元素,則返回 true。
boolean isEmpty()
// 返回在此 set 的元素上以升序進行迭代的迭代器。
Iterator<E> iterator()
// 返回此 set 中當前最后一個(最高)元素。
E last()
// 返回此 set 中嚴格小於給定元素的最大元素;如果不存在這樣的元素,則返回 null。
E lower(E e)
// 獲取並移除第一個(最低)元素;如果此 set 為空,則返回 null。
E pollFirst()
// 獲取並移除最后一個(最高)元素;如果此 set 為空,則返回 null。
E pollLast()
// 如果此 set 中存在指定的元素,則將其移除。
boolean remove(Object o)
// 從此 set 中移除包含在指定 collection 中的所有元素。
boolean removeAll(Collection<?> c)
// 返回此 set 中的元素數目。
int size()
// 返回此 set 的部分視圖,其元素范圍從 fromElement 到 toElement。
NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive)
// 返回此 set 的部分視圖,其元素從 fromElement(包括)到 toElement(不包括)。
NavigableSet<E> subSet(E fromElement, E toElement)
// 返回此 set 的部分視圖,其元素大於等於 fromElement。
NavigableSet<E> tailSet(E fromElement)
// 返回此 set 的部分視圖,其元素大於(或等於,如果 inclusive 為 true)fromElement。
NavigableSet<E> tailSet(E fromElement, boolean inclusive)
復制代碼

 

ConcurrentSkipListSet源碼(JDK1.7.0_40版本)

ConcurrentSkipListSet.java的完整源碼如下:

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

ConcurrentSkipListSet是通過ConcurrentSkipListMap實現的,它的接口基本上都是通過調用ConcurrentSkipListMap接口來實現的。這里就不再對它的源碼進行分析了。

 

ConcurrentSkipListSet示例

復制代碼
 1 import java.util.*;
 2 import java.util.concurrent.*;
 3 
 4 /*
 5  *   ConcurrentSkipListSet是“線程安全”的集合,而TreeSet是非線程安全的。
 6  *
 7  *   下面是“多個線程同時操作並且遍歷集合set”的示例
 8  *   (01) 當set是ConcurrentSkipListSet對象時,程序能正常運行。
 9  *   (02) 當set是TreeSet對象時,程序會產生ConcurrentModificationException異常。
10  *
11  * @author skywang
12  */
13 public class ConcurrentSkipListSetDemo1 {
14 
15     // TODO: set是TreeSet對象時,程序會出錯。
16     //private static Set<String> set = new TreeSet<String>();
17     private static Set<String> set = new ConcurrentSkipListSet<String>();
18     public static void main(String[] args) {
19     
20         // 同時啟動兩個線程對set進行操作!
21         new MyThread("a").start();
22         new MyThread("b").start();
23     }
24 
25     private static void printAll() {
26         String value = null;
27         Iterator iter = set.iterator();
28         while(iter.hasNext()) {
29             value = (String)iter.next();
30             System.out.print(value+", ");
31         }
32         System.out.println();
33     }
34 
35     private static class MyThread extends Thread {
36         MyThread(String name) {
37             super(name);
38         }
39         @Override
40         public void run() {
41                 int i = 0;
42             while (i++ < 10) {
43                 // “線程名” + "序號"
44                 String val = Thread.currentThread().getName() + (i%6);
45                 set.add(val);
46                 // 通過“Iterator”遍歷set。
47                 printAll();
48             }
49         }
50     }
51 }
復制代碼

(某一次)運行結果

復制代碼
a1, b1, 
a1, a1, a2, b1, 
b1, a1, a2, a3, b1,

a1, a2, a3, a1, a4, b1, b2, 
a2, a1, a2, a3, a4, a5, b1, b2, 
a3, a0, a4, a5, a1, b1, a2, b2, 
a3, a0, a4, a1, a5, a2, b1, a3, b2, a4, b3, 
a5, a0, b1, a1, b2, a2, b3, 
a3, a0, a4, a1, a5, a2, b1, a3, b2, a4, b3, a5, b4, 
b1, a0, b2, a1, b3, a2, b4, 
a3, a0, a4, a1, a5, a2, b1, a3, b2, a4, b3, a5, b4, b1, b5, 
b2, a0, a1, a2, a3, a4, a5, b3, b1, b4, b2, b5, 
b3, a0, b4, a1, b5, 
a2, a0, a3, a1, a4, a2, a5, a3, b0, a4, b1, a5, b2, b0, b3, b1, b4, b2, b5, b3, 
b4, a0, b5, 
a1, a2, a3, a4, a5, b0, b1, b2, b3, b4, b5, 
a0, a1, a2, a3, a4, a5, b0, b1, b2, b3, b4, b5, 
a0, a1, a2, a3, a4, a5, b0, b1, b2, b3, b4, b5, 
a0, a1, a2, a3, a4, a5, b0, b1, b2, b3, b4, b5, 
復制代碼

結果說明
示例程序中,啟動兩個線程(線程a和線程b)分別對ConcurrentSkipListSet進行操作。以線程a而言,它會先獲取“線程名”+“序號”,然后將該字符串添加到ConcurrentSkipListSet集合中;接着,遍歷並輸出集合中的全部元素。 線程b的操作和線程a一樣,只不過線程b的名字和線程a的名字不同。
當set是ConcurrentSkipListSet對象時,程序能正常運行。如果將set改為TreeSet時,程序會產生ConcurrentModificationException異常。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM