Java专栏: 线程并发安全中你须掌握的CopyOnWriteList

Part1CopyOnWriteList简介

ArrayList是线程不安全的,于是JDK新增加了一个线程并发安全的List——CopyOnWriteList,中心思想就是copy-on-write,简单来说是读写分离:读时共享、写时复制(原本的array)更新(且为独占式的加锁),而我们下面分析的源码具体实现也是这个思想的体现。

继承体系:

我们单独看一下CopyOnWriteList的主要属性和下面要主要分析的方法有哪些。从图中看出:

  • 每个CopyOnWriteList对象里面有一个array数组来存放具体元素

  • 使用ReentrantLock独占锁来保证只有写线程对array副本进行更新。

  • CopyOnWriteArrayList在遍历的使用不会抛出ConcurrentModificationException异常,并且遍历的时候就不用额外加锁

下面还是主要看CopyOnWriteList的实现

成员属性

//这个就是保证更新数组的时候只有一个线程能够获取lock,然后更新
final transient ReentrantLock lock = new ReentrantLock();
/*
使用volatile修饰的array,保证写线程更新array之后别的线程能够看到更新后的array.
但是并不能保证实时性:在数组副本上添加元素之后,还没有更新array指向新地址之前,别的读线程看到的还是旧的array
*/
private transient volatile Object[] array;
//获取数组,非private的,final修饰
final Object[] getArray() {
    return array;
}
//设置数组
final void setArray(Object[] a) {
    array = a;
}

构造方法

(1)无参构造,默认创建的是一个长度为0的数组

/*这里就是构造方法,创建一个新的长度为0的Object数组
然后调用setArray方法将其设置给CopyOnWriteList的成员变量array*/
public CopyOnWriteArrayList() {
    setArray(new Object[0]);
}

(2)参数为Collection的构造方法

//按照集合的迭代器遍历返回的顺序,创建包含传入的collection集合的元素的列表
//如果传递的参数为null,会抛出异常
public CopyOnWriteArrayList(Collection<? extends E> c) {
    Object[] elements; //一个elements数组
    //这里是判断传递的是否就是一个CopyOnWriteArrayList集合
    if (c.getClass() == CopyOnWriteArrayList.class)
        //如果是,直接调用getArray方法,获得传入集合的array然后赋值给elements
        elements = ((CopyOnWriteArrayList<?>)c).getArray();
    else {
        //先将传入的集合转变为数组形式
        elements = c.toArray();
        //c.toArray()可能不会正确地返回一个 Object[]数组,那么使用Arrays.copyOf()方法
        if (elements.getClass() != Object[].class)
            elements = Arrays.copyOf(elements, elements.length, Object[].class);
    }
    //直接调用setArray方法设置array属性
    setArray(elements);
}

(3)创建一个包含给定数组副本的list

public CopyOnWriteArrayList(E[] toCopyIn) {
    setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
}

上面介绍的是CopyOnWriteList的初始化,三个构造方法都比较易懂,后面还是主要看看几个主要方法的实现

添加元素

下面是add(E e)方法的实现 ,以及详细注释

public boolean add(E e) {
    //获得独占锁
    final ReentrantLock lock = this.lock;
    //加锁
    lock.lock();
    try {
        //获得list底层的数组array
        Object[] elements = getArray();
        //获得数组长度
        int
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值