(三)并发-集合LIST(CopyOnWriteArrayList)

81 阅读2分钟

继承关系

图片.png CopyOnWriteArrayList是并发包下的集合类

`Iterable`可进行迭代器迭代
`Collection`拥有集合的一般特性和方法
`List`说明底层是数组存储元素
`Cloneable`可以被克隆
`RandomAccess`通过索引可随机访问

CopyOnWriteArrayList底层维护了一个transient volatile Object[] array数组和一个 transient Object lock = new Object()锁,对于所有的读操作是进行无锁化处理,及时返回原始数组中索引的值,可接受并发,对于写操作需要先获取lock的权限,获取到相关的权限之后,Copy一份原始数组进行写操作,并且写完成之后释放lock,并把array的引用指向新的数组,同时 volatile 保证了每个线程在写操作进行复制的数组为最新。对于读操作时进行写并不影响,读是被复制的集合,而不是最新的集合,这就可能导致数据的前后不一致问题,对于写操作,CopyOnWriteArrayList效率较低同时会占用相当一部分内存,所以适合 读多写少的场景。

添加元素

//添加元素的操作
public boolean add(E e) {  
    //先获取锁获取操作权限
    synchronized (lock) {  
        //获取原始集合
        Object[] es = getArray();  
        //原始集合数组长度+1
        int len = es.length;  
        //创建 len 长度的集合并复制原始集合元素到新集合
        es = Arrays.copyOf(es, len + 1);  
        //添加元素到新集合的最后的位置
        es[len] = e;  
        //设置array的引用为新集合的地址
        setArray(es);  
        //返回成功标志
        return true;  
    }  
    //释放锁资源
}

修改元素

public E set(int index, E element) {  
    //先获取锁获取操作权限
    synchronized (lock) {  
        //获取原始集合
        Object[] es = getArray();  
        //获取index角标处的原始值
        E oldValue = elementAt(es, index);  
        //如果原始值和新值相等不做任何操作
        if (oldValue != element) {  
            //不相等进行一份浅拷贝
            es = es.clone();  
            //替换原始元素
            es[index] = element;  
        }  
        //设置array的引用为新集合的地址
        setArray(es);  
        //返回原始值
        return oldValue;  
    }  
    //释放锁资源
}

删除元素

public E remove(int index) {  
    //先获取锁获取操作权限
    synchronized (lock) {  
        //获取原始集合
        Object[] es = getArray();  
        //原始集合的长度
        int len = es.length;  
        //获取原始index的值
        E oldValue = elementAt(es, index);  
        int numMoved = len - index - 1;  
        Object[] newElements;  
        //说明移除的是最后一个元素
        if (numMoved == 0)  
            //直接copy len - 1 长度的原始集合
            newElements = Arrays.copyOf(es, len - 1);  
        else {  
            //不是最后一个元素,创建新数组 长度为len - 1
            newElements = new Object[len - 1];  
            //拷贝0-index元素到新集合
            System.arraycopy(es, 0, newElements, 0, index);  
            //拷贝index + 1 之后的所有元素到新集合
            System.arraycopy(es, index + 1, newElements, index, numMoved);  
        }  
        //将新引用赋值给array
        setArray(newElements);  
        //返回原始值
        return oldValue;  
    }  
     //释放锁资源
}