• 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的代码进行详细的解析了。

  • 相关阅读:
    一转眼,十年间~~~
    怎样安装PHPnow,并开始使用?
    js的事件类型
    ie兼容性问题 前传
    外层div撑不开的解决办法
    CSS3 新属性搜罗整理
    webApp学习之路
    花式使用CSS3 transition
    20种新颖的按钮风格和效果【附源码】
    酷酷的文本效果
  • 原文地址:https://www.cnblogs.com/xiaolovewei/p/9142046.html
Copyright © 2020-2023  润新知