CopyOnWriteArrayList原理

2021-01-29  本文已影响0人  给代码点颜色

简介

长时间不关注底层信息,导致面试的时候竟然忘了这个list的实现原理,这里做下记录,以夯实基础。

CopyOnWriteArrayList是线程安全的,只在写的时候会加锁,适用多读少写的场景。主要有两个属性,一个是ReentrantLock,一个是Object[]。

CopyOnWriteArrayList内部是以数组存储数据,Object[]就是对应数组的引用。
ReentrantLock为写锁,保证同一时刻只有一个线程在修改CopyOnWriteArrayList。

代码分析

Object[]定义

private transient volatile Object[] array;

volatile

add数据之后,array引用会被替换为新数组。使用volatile修饰,保证读取的数组信息为最新。

transient

序列化对象的时候这个属性不序列化。

ReentrantLock定义

写锁。

final transient ReentrantLock lock = new ReentrantLock();

add操作

原理

add数据的时候,会先加锁,然后拷贝旧数组内容到新数组,这里新数组比旧数组长度大1。之后在新数组最后一位放入add的数据,并替换array引用,解锁。

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();
        }
    }

从源码可以看出,CopyOnWriteArrayList每次add的时候都会新建一个数组,并发生一次拷贝动作。所以如果可以,尽量创建的时候就传入所有元素或者使用addAll批量加入。

注意

subList读的只是CopyOnWriteArrayList的一段引用,如果CopyOnWriteArrayList此引用区间内数据变化,迭代子list的时候也会读到新数据。

上一篇下一篇

猜你喜欢

热点阅读