概要
本章對Java.util.concurrent包中的ConcurrentSkipListSet類進行詳細的介紹。內容包括:
ConcurrentSkipListSet介紹
ConcurrentSkipListSet原理和數據結構
ConcurrentSkipListSet函數列表
ConcurrentSkipListSet源碼(JDK1.7.0_40版本)
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的完整源碼如下:

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異常。