深刻Java集合学习系列:深刻CopyOnWriteArraySet

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数组

 

CopyOnWriteArraySet介绍

它是线程安全的无序的集合,能够将它理解成线程安全的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原理和数据结构

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.7.0_40版本)

CopyOnWriteArraySet.java的完整源码以下:ide

  View Code

CopyOnWriteArraySet是经过CopyOnWriteArrayList实现的,它的API基本上都是经过调用CopyOnWriteArrayList的API来实现的。相信对CopyOnWriteArrayList了解的话,对CopyOnWriteArraySet的了解是水到渠成的事;因此,这里就再也不对CopyOnWriteArraySet的代码进行详细的解析了。若对CopyOnWriteArrayList不了解,请参考“Java多线程系列--“JUC集合”02之 CopyOnWriteArrayList”。函数

 

CopyOnWriteArraySet示例

下面,咱们经过一个例子去对比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异常。

 


更多内容

1. Java多线程系列--“JUC集合”01之 框架

2. Java多线程系列--“JUC集合”02之 CopyOnWriteArrayLis

3. Java多线程系列目录(共xx篇)

4. Java 集合系列目录(Category)

相关文章
相关标签/搜索