http://www.cnblogs.com/skywang12345/p/3498497.html?utm_source=tuicoolhtml
本章是JUC系列中的CopyOnWriteArraySet篇。接下來,會先對CopyOnWriteArraySet進行基本介紹,而後再說明它的原理,接着經過代碼去分析,最後經過示例更進一步的瞭解CopyOnWriteArraySet。內容包括:
CopyOnWriteArraySet介紹
CopyOnWriteArraySet原理和數據結構
CopyOnWriteArraySet函數列表
CopyOnWriteArraySet源碼(JDK1.7.0_40版本)
CopyOnWriteArraySet示例java
轉載請註明出處:http://www.cnblogs.com/skywang12345/p/3498497.html數組
它是線程安全的無序的集合,能夠將它理解成線程安全的HashSet。有意思的是,CopyOnWriteArraySet和HashSet雖然都繼承於共同的父類AbstractSet;可是,HashSet是經過「散列表(HashMap)」實現的,而CopyOnWriteArraySet則是經過「動態數組(CopyOnWriteArrayList)」實現的,並非散列表。
和CopyOnWriteArrayList相似,CopyOnWriteArraySet具備如下特性:
1. 它最適合於具備如下特徵的應用程序:Set 大小一般保持很小,只讀操做遠多於可變操做,須要在遍歷期間防止線程間的衝突。
2. 它是線程安全的。
3. 由於一般須要複製整個基礎數組,因此可變操做(add()、set() 和 remove() 等等)的開銷很大。
4. 迭代器支持hasNext(), next()等不可變操做,但不支持可變 remove()等 操做。
5. 使用迭代器進行遍歷的速度很快,而且不會與其餘線程發生衝突。在構造迭代器時,迭代器依賴於不變的數組快照。安全
建議:在學習CopyOnWriteArraySet以前,先經過"Java 集合系列16之 HashSet詳細介紹(源碼解析)和使用示例"對HashSet進行了解。數據結構
CopyOnWriteArraySet的數據結構,以下圖所示:多線程
說明:
1. CopyOnWriteArraySet繼承於AbstractSet,這就意味着它是一個集合。
2. CopyOnWriteArraySet包含CopyOnWriteArrayList對象,它是經過CopyOnWriteArrayList實現的。而CopyOnWriteArrayList本質是個動態數組隊列,
因此CopyOnWriteArraySet至關於經過經過動態數組實現的「集合」! CopyOnWriteArrayList中容許有重複的元素;可是,CopyOnWriteArraySet是一個集合,因此它不能有重複集合。所以,CopyOnWriteArrayList額外提供了addIfAbsent()和addAllAbsent()這兩個添加元素的API,經過這些API來添加元素時,只有當元素不存在時才執行添加操做!
至於CopyOnWriteArraySet的「線程安全」機制,和CopyOnWriteArrayList同樣,是經過volatile和互斥鎖來實現的。這個在前一章節介紹CopyOnWriteArrayList時數據結構時,已經進行了說明,這裏就再也不重複敘述了。框架
// 建立一個空 set。 CopyOnWriteArraySet() // 建立一個包含指定 collection 全部元素的 set。 CopyOnWriteArraySet(Collection<? extends E> c) // 若是指定元素並不存在於此 set 中,則添加它。 boolean add(E e) // 若是此 set 中沒有指定 collection 中的全部元素,則將它們都添加到此 set 中。 boolean addAll(Collection<? extends E> c) // 移除此 set 中的全部元素。 void clear() // 若是此 set 包含指定元素,則返回 true。 boolean contains(Object o) // 若是此 set 包含指定 collection 的全部元素,則返回 true。 boolean containsAll(Collection<?> c) // 比較指定對象與此 set 的相等性。 boolean equals(Object o) // 若是此 set 不包含任何元素,則返回 true。 boolean isEmpty() // 返回按照元素添加順序在此 set 中包含的元素上進行迭代的迭代器。 Iterator<E> iterator() // 若是指定元素存在於此 set 中,則將其移除。 boolean remove(Object o) // 移除此 set 中包含在指定 collection 中的全部元素。 boolean removeAll(Collection<?> c) // 僅保留此 set 中那些包含在指定 collection 中的元素。 boolean retainAll(Collection<?> c) // 返回此 set 中的元素數目。 int size() // 返回一個包含此 set 全部元素的數組。 Object[] toArray() // 返回一個包含此 set 全部元素的數組;返回數組的運行時類型是指定數組的類型。 <T> T[] toArray(T[] a)
CopyOnWriteArraySet.java的完整源碼以下:ide
CopyOnWriteArraySet是經過CopyOnWriteArrayList實現的,它的API基本上都是經過調用CopyOnWriteArrayList的API來實現的。相信對CopyOnWriteArrayList瞭解的話,對CopyOnWriteArraySet的瞭解是水到渠成的事;因此,這裏就再也不對CopyOnWriteArraySet的代碼進行詳細的解析了。若對CopyOnWriteArrayList不瞭解,請參考「Java多線程系列--「JUC集合」02之 CopyOnWriteArrayList」。函數
下面,咱們經過一個例子去對比HashSet和CopyOnWriteArraySet。學習
import java.util.*; import java.util.concurrent.*; /* * CopyOnWriteArraySet是「線程安全」的集合,而HashSet是非線程安全的。 * * 下面是「多個線程同時操做而且遍歷集合set」的示例 * (01) 當set是CopyOnWriteArraySet對象時,程序能正常運行。 * (02) 當set是HashSet對象時,程序會產生ConcurrentModificationException異常。 * * @author skywang */ public class CopyOnWriteArraySetTest1 { // TODO: set是HashSet對象時,程序會出錯。 //private static Set<String> set = new HashSet<String>(); private static Set<String> set = new CopyOnWriteArraySet<String>(); public static void main(String[] args) { // 同時啓動兩個線程對set進行操做! new MyThread("ta").start(); new MyThread("tb").start(); } private static void printAll() { String value = null; Iterator iter = set.iterator(); while(iter.hasNext()) { value = (String)iter.next(); System.out.print(value+", "); } System.out.println(); } private static class MyThread extends Thread { MyThread(String name) { super(name); } @Override public void run() { int i = 0; while (i++ < 10) { // 「線程名」 + "-" + "序號" String val = Thread.currentThread().getName() + "-" + (i%6); set.add(val); // 經過「Iterator」遍歷set。 printAll(); } } } }
(某一次)運行結果:
ta-1, tb-1, ta-1, tb-1, ta-1, tb-1, ta-1, ta-2, tb-1, ta-1, ta-2, tb-1, tb-2, ta-2, ta-1, tb-2, tb-1, ta-3, ta-2, ta-1, tb-2, tb-1, ta-3, ta-2, tb-3, tb-2, ta-1, ta-3, tb-1, tb-3, ta-2, ta-4, tb-2, ta-1, ta-3, tb-1, tb-3, ta-2, ta-4, tb-2, tb-4, ta-3, ta-1, tb-3, tb-1, ta-4, ta-2, tb-4, tb-2, ta-5, ta-3, ta-1, tb-3, tb-1, ta-4, ta-2, tb-4, tb-2, ta-5, ta-3, tb-5, tb-3, ta-1, ta-4, tb-1, tb-4, ta-2, ta-5, tb-2, tb-5, ta-3, ta-0, tb-3, ta-1, ta-4, tb-1, tb-4, ta-2, ta-5, tb-2, tb-5, ta-3, ta-0, tb-3, tb-0, ta-4, ta-1, tb-4, tb-1, ta-5, ta-2, tb-5, tb-2, ta-0, ta-3, tb-0, tb-3, ta-1, ta-4, tb-1, tb-4, ta-2, ta-5, tb-5, ta-0, tb-0, ta-1, tb-2, tb-1, ta-3, ta-2, tb-3, tb-2, ta-4, ta-3, tb-4, tb-3, ta-5, ta-4, tb-5, tb-4, ta-0, ta-5, tb-0, tb-5, ta-1, ta-0, tb-1, tb-0, ta-2, ta-1, tb-2, tb-1, ta-3, ta-2, tb-3, tb-2, ta-4, ta-3, tb-4, tb-3, ta-5, tb-5, ta-0, tb-0, ta-4, ta-1, tb-4, tb-1, ta-5, ta-2, tb-5, tb-2, ta-0, ta-3, tb-0, tb-3, ta-1, ta-4, tb-1, tb-4, ta-2, ta-5, tb-2, tb-5, ta-3, ta-0, tb-3, tb-0, ta-4, tb-4, ta-5, tb-5, ta-0, tb-0,
結果說明:
因爲set是集合對象,所以它不會包含重複的元素。
若是將源碼中的set改爲HashSet對象時,程序會產生ConcurrentModificationException異常。
更多內容