並發容器之ConcurrentSkipListSet


概要

本章對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的完整源碼如下:

  View Code

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