Java多線程系列--CopyOnWriteArraySet


轉載:http://www.cnblogs.com/skywang12345/p/3498497.html

概要

本章是JUC系列中的CopyOnWriteArraySet篇。接下來,會先對CopyOnWriteArraySet進行基本介紹,然后再說明它的原理,接着通過代碼去分析,最后通過示例更進一步的了解CopyOnWriteArraySet。內容包括:
CopyOnWriteArraySet介紹
CopyOnWriteArraySet原理和數據結構
CopyOnWriteArraySet函數列表
CopyOnWriteArraySet源碼

 

 

CopyOnWriteArraySet介紹

它是線程安全的無序的集合,可以將它理解成線程安全的HashSet。有意思的是,CopyOnWriteArraySet和HashSet雖然都繼承於共同的父類AbstractSet;但是,HashSet是通過“散列表(HashMap)”實現的,而CopyOnWriteArraySet則是通過“動態數組(CopyOnWriteArrayList)”實現的,並不是散列表。
和CopyOnWriteArrayList類似,其實CopyOnWriteSet底層包含一個CopyOnWriteList,幾乎所有操作都是借助CopyOnWriteList,就像HashSet包含HashMap

CopyOnWriteArraySet具有以下特性:
1. 它最適合於具有以下特征的應用程序:Set 大小通常保持很小,只讀操作遠多於可變操作,需要在遍歷期間防止線程間的沖突。
2. 它是線程安全的。
3. 因為通常需要復制整個基礎數組,所以可變操作(add()、set() 和 remove() 等等)的開銷很大。
4. 迭代器支持hasNext(), next()等不可變操作,但不支持可變 remove()等 操作。
5. 使用迭代器進行遍歷的速度很快,並且不會與其他線程發生沖突。在構造迭代器時,迭代器依賴於不變的數組快照。

 

 

CopyOnWriteArraySet原理和數據結構

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

說明
  1. CopyOnWriteArraySet繼承於AbstractSet,這就意味着它是一個集合。
  2. CopyOnWriteArraySet包含CopyOnWriteArrayList對象,它是通過CopyOnWriteArrayList實現的。而CopyOnWriteArrayList本質是個動態數組隊列,
所以CopyOnWriteArraySet相當於通過通過動態數組實現的“集合”! CopyOnWriteArrayList中允許有重復的元素;但是,CopyOnWriteArraySet是一個集合,所以它不能有重復集合。因此,CopyOnWriteArrayList額外提供了addIfAbsent()和addAllAbsent()這兩個添加元素的API,通過這些API來添加元素時,只有當元素不存在時才執行添加操作!
   至於CopyOnWriteArraySet的“線程安全”機制,和CopyOnWriteArrayList一樣,是通過volatile和互斥鎖來實現的。這個在前一章節介紹CopyOnWriteArrayList時數據結構時,已經進行了說明,這里就不再重復敘述了。

 

CopyOnWriteArraySet函數列表

復制代碼
// 創建一個空 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源碼(JDK1.8版本)

CopyOnWriteArraySet.java的完整源碼如下:

 public class CopyOnWriteArraySet<E> extends AbstractSet<E>
                implements java.io.Serializable {
            private static final long serialVersionUID = 5457747651344034263L;

            private final CopyOnWriteArrayList<E> al;

            /**
             * Creates an empty set.
             */
            public CopyOnWriteArraySet() {
                al = new CopyOnWriteArrayList<E>();
            }

            /
            public CopyOnWriteArraySet(Collection<? extends E> c) {
                if (c.getClass() == CopyOnWriteArraySet.class) {
                    @SuppressWarnings("unchecked") CopyOnWriteArraySet<E> cc =
                            (CopyOnWriteArraySet<E>)c;
                    al = new CopyOnWriteArrayList<E>(cc.al);
                }
                else {
                    al = new CopyOnWriteArrayList<E>();
                    al.addAllAbsent(c);
                }
            }

            
            public int size() {
                return al.size();
            }

            
            public boolean isEmpty() {
                return al.isEmpty();
            }

           
            public boolean contains(Object o) {
                return al.contains(o);
            }

            public Object[] toArray() {
                return al.toArray();
            }

            public <T> T[] toArray(T[] a) {
                return al.toArray(a);
            }

          
            public void clear() {
                al.clear();
            }

            public boolean remove(Object o) {
                return al.remove(o);
            }

//這里添加時,為了避免重復元素,調用的不是CopyOnWriteList的add方法,而是另外一個去重的方法
public boolean add(E e) { return al.addIfAbsent(e); } public boolean containsAll(Collection<?> c) { return al.containsAll(c); } public boolean addAll(Collection<? extends E> c) { return al.addAllAbsent(c) > 0; } public boolean removeAll(Collection<?> c) { return al.removeAll(c); } public boolean retainAll(Collection<?> c) { return al.retainAll(c); } public Iterator<E> iterator() { return al.iterator(); } public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Set)) return false; Set<?> set = (Set<?>)(o); Iterator<?> it = set.iterator(); // Uses O(n^2) algorithm that is only appropriate // for small sets, which CopyOnWriteArraySets should be. // Use a single snapshot of underlying array Object[] elements = al.getArray(); int len = elements.length; // Mark matched elements to avoid re-checking boolean[] matched = new boolean[len]; int k = 0; outer: while (it.hasNext()) { if (++k > len) return false; Object x = it.next(); for (int i = 0; i < len; ++i) { if (!matched[i] && eq(x, elements[i])) { matched[i] = true; continue outer; } } return false; } return k == len; } public boolean removeIf(Predicate<? super E> filter) { return al.removeIf(filter); } public void forEach(Consumer<? super E> action) { al.forEach(action); } public Spliterator<E> spliterator() { return Spliterators.spliterator (al.getArray(), Spliterator.IMMUTABLE | Spliterator.DISTINCT); } /** * Tests for equality, coping with nulls. */ private static boolean eq(Object o1, Object o2) { return (o1 == null) ? o2 == null : o1.equals(o2); } }

 

CopyOnWriteArraySet是通過CopyOnWriteArrayList實現的,它的API基本上都是通過調用CopyOnWriteArrayList的API來實現的。相信對CopyOnWriteArrayList了解的話,對CopyOnWriteArraySet的了解是水到渠成的事;所以,這里就不再對CopyOnWriteArraySet的代碼進行詳細的解析了。


免責聲明!

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



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