CopyOnWriteArrayList源码解析

  • 依据jdk1.8源码分析

新建

  • 创建一个零长度数组
private transient volatile Object[] array;//底层数据

添加数据

  • 先上同步锁
  • 对原始数组进行拷贝(浅拷贝),然后在拷贝后的数组上进行修改
  • 将修改后的结果赋值给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();
        }
    }

获取数据

  • 获取的时候没有加锁(由于array是volatile,所以会先从主内存更新数据,所以线程中的数据应该始终都是最新的)

删除数据

  • 先上同步锁
  • 对原始数据进行拷贝,在拷贝的时候不拷贝那个需要删除的数据
  • 将修改后的结果赋值给array
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();
        }
    }

遍历数据

  • 使用listIterator()获取迭代器
  • listIterator()中将array赋给COWIterator(实现了ListIterator)。这里没有进行复制是因为如果数据有修改将生成一个新数组,而迭代中的数组将是一个过时的数组
  • 可以调用hasNext() hasPrevious() next() previous()
  • 注意:set() add() remove()都会直接抛出异常UnsupportedOperationException

总结

  • 由于每次删除和增加元素都会拷贝一个新的数组出来,因此原本数组中的元素已经过时。所以即使这个时候另一个线程修改数据,也不会报错,只是数据不是最新的
  • 增删改上锁、读不上锁
  • 由于每一次修改都会有新的数组,array使用volatile修饰,所以在读的时候能确保使用的到的是最新的数组副本(多线程的情况下始终都是在主内存中读取)

参考jdk1.8源码
https://www.cnblogs.com/java-zhao/p/5121944.html

猜你喜欢

转载自blog.csdn.net/designer01/article/details/82859518