深入学习java并发编程:CopyOnWriteArrayList<E>实现

原创 2016年05月30日 21:44:51
1、CopyOnWriteArrayList涉及类图

     Copy-On-Write简称COW,是一种用于程序设计中的优化策略。其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改,这是一种延时懒惰策略。从JDK1.5开始Java并发包里提供了两个使用CopyOnWrite机制实现的并发容器,它们是CopyOnWriteArrayList和CopyOnWriteArraySet。CopyOnWrite容器非常有用,可以在非常多的并发场景中使用到。    
         CopyOnWriteArrayList是一个线程安全、并且在读操作式无锁的ArrayList容器,当我们往其中添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。

2、CopyOnWriteArrayList的构造实现以及重要方法 
    transient final ReentrantLock lock = new ReentrantLock();
    private volatile transient Object[] array;
    以上两个是CopyOnWriteArrayList类中两个重要的数据成员, Object[] array是存放列表对象的数组,可以看到使用ReentrantLock来控制并发的对arrayList进行修改。
 1) 构造器
       CopyOnWriteArrayList提供了3个构造器 
//默认的无参数构造器,可以看到这里与ArrayList不同,arrayList创建大小为10的数组,而CopyOnWriteArrayList创建一个大小为0的数组。
 public CopyOnWriteArrayList() {
        setArray(new Object[0]);
    }
//根据提供的Collection ,来创建CopyOnWriteArrayList
 public CopyOnWriteArrayList(Collection<? extends E> c) {
        Object[] elements = c.toArray();
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elements.getClass() != Object[].class)
            elements = Arrays.copyOf(elements, elements.length, Object[].class);
        setArray(elements);
    }
//根据已有的泛型数组,创建CopyOnWriteArrayList
 public CopyOnWriteArrayList(E[] toCopyIn) {
        setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
    }
2)add(E e): boolean  添加元素的方法
//add方法并没有使用synchronized关键字,而是使用了ReentrantLock 来保证线程安全的,不同于ArrayList,这里每次都会创建一个新的Object数组(写时复制),,此数组大小为当前数组大小加1,将之前数组内容复制到新数组中,并将新元素添加到数组末尾,最后将引用赋值给全局数组对象。通过volatile语义保证可见性。
 public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }
3)remove(Object o): boolean 移除元素方法
//与add方法一样,此方法也是通过ReentrantLock 锁来保证线程安全,但他和ArrayList所采用的方法不同,首先创建一个比当前数组小1的Object数组,然后移除目标元素,复制其他元素,最后将引用赋值给全局数组对象。
public E remove(int index) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            E oldValue = get(elements, index);
            int numMoved = len - index - 1;
            if (numMoved == 0)
                setArray(Arrays.copyOf(elements, len - 1));
            else {
                Object[] newElements = new Object[len - 1];
                System.arraycopy(elements, 0, newElements, 0, index);
                System.arraycopy(elements, index + 1, newElements, index,
                                 numMoved);
                setArray(newElements);
            }
            return oldValue;
        } finally {
            lock.unlock();
        }
    }
4)get(int index): E 
//此方法非常简单,直接获取当前数组对应位置的元素,并没有加锁保护,读取的是当时的一个镜像,因此可能出现脏读现象,但是相对而言,读的性能会比较高。
 public E get(int index) {
        return get(getArray(), index);
    }

5)addIfAbsent(E e): boolean 如果不存在,则添加元素方法
public boolean addIfAbsent(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            // Copy while checking if already present.
            // This wins in the most common case where it is not present
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = new Object[len + 1];
            for (int i = 0; i < len; ++i) {
                if (eq(e, elements[i]))
                    return false; // exit, throwing away copy
                else
                    newElements[i] = elements[i];
            }
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }
6)iterator(): Iterator<E>  获取遍历列表的迭代器方法
// 调用iterator方法后创建一个COWIterator对象实例,保存一个当前数组的快照,在调用next方法遍历时则仅对此快照数据进行遍历,因此遍历
CopyOnWriteArrayList时不会抛出ConcurrentModificationException。
 public Iterator<E> iterator() {
        return new COWIterator<E>(getArray(), 0);
    }








深入Java集合系列之六:CopyOnWriteArrayList

CopyOnWriteArrayList简介CopyOnWriteArrayList容器是Collections.synchronizedList(List list)的替代方案,CopyOnWrit...
  • u011116672
  • u011116672
  • 2016年04月08日 16:18
  • 3410

Java并发编程学习路线图

思维导图如下:
  • csujiangyu
  • csujiangyu
  • 2016年05月18日 10:08
  • 832

Java并发编程与技术内幕:线程池深入理解

首先,讲讲什么是线程池?照笔者的简单理解,其实就是一组线程实时处理休眠状态,等待唤醒执行。那么为什么要有线程池这个东西呢?可以从以下几个方面来考虑:其一、减少在创建和销毁线程上所花的时间以及系统资源的...
  • Evankaka
  • Evankaka
  • 2016年06月08日 08:38
  • 17209

CopyOnWriteArrayList 并发集合源码分析

在CopyOnWriteArrayList里处理写操作(包括add、remove、set等)是先将原始的数据通过JDK1.6的Arrays.copyof()来生成一份新的数组 然后在新的数据对象上进...
  • likailonghaha
  • likailonghaha
  • 2016年11月30日 11:37
  • 657

《深入理解计算机系统》--并发编程

这也是一本很出名的书,在很早的时候读过一些,这次从后面开始读,看有没有新的体会。     如果逻辑流在时间上重叠,那么他们就是并发的,硬件异常处理程序、进程和UNIX信号处理程序都是熟悉的例子。并发...
  • yusiguyuan
  • yusiguyuan
  • 2013年10月13日 14:09
  • 2124

java深入学习(一)

为什么接口要规定成员变量必须是public static final的呢? 答: 首先接口是一种高度抽象的”模版”,,而接口中的属性也就是’模版’的成员,就应当是所有实现”模版”的实现类的共有特性...
  • Luxia_24
  • Luxia_24
  • 2015年09月09日 15:34
  • 1511

《Java并发编程的艺术》读书笔记——Java内存模型

第三章 Java内存模型3.1 内存模型基础3.1.1 并发编程的两个关键问题 线程之间如何通信 java采用共享内存模型隐式通信 线程之间如何同步 共享内存模型模型需要显式指定同步 3.1.2 ...
  • shuxiangxingkong
  • shuxiangxingkong
  • 2016年09月13日 10:49
  • 391

【Java并发编程的艺术】【学习笔记】并发基础

2、并发基础2.1、AQS​ 队列同步器AbstractQueuedSynchronizer(以下简称同步器),是用来构建锁或者其他同步组件的基础框架,它使用了一个int成员变量表示同步状态,通过...
  • wengcheng_k
  • wengcheng_k
  • 2017年12月28日 21:41
  • 56

CopyOnWriteArrayList排序问题

在多线程中,使用ArrayList 进行remove操作时,会报异常。 CopyOnWriteArrayList,是线程安全的集合,但有个缺点:使用Collections.sort(copyOnWr...
  • liuxiao723846
  • liuxiao723846
  • 2017年01月20日 18:24
  • 535

java并发编程学习总结(基础篇)

一、基础概念总结 1.多线程程序可能存在的风险: (1)安全性问题:多线程程序在没有充足同步的情况下,在特定的线程执行时序下,多个线程同时操作一块共享资源时,可能引发错误。 (2)活跃性问题...
  • lantian0802
  • lantian0802
  • 2014年02月16日 14:52
  • 1807
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深入学习java并发编程:CopyOnWriteArrayList<E>实现
举报原因:
原因补充:

(最多只允许输入30个字)