Java底层类和源码分析系列-CopyOnWriteArrayList底层架构和源码分析

ArrayList是非线程安全的,Vector虽是线程安全的,但由于简单粗暴的锁同步机制,性能较差。而CopyOnWriteArrayList则提供了另一种不同的并发处理策略(当然是针对特定的并发场景)。

很多时候,我们的系统应对的都是读多写少的并发场景。CopyOnWriteArrayList容器允许并发读,读操作是无锁的,性能较高。至于写操作,比如向容器中添加一个元素,则首先将当前容器复制一份,然后在新副本上执行写操作,结束之后再将原容器的引用指向新容器。

几个要点

  • 在写时进行复制的线程安全ArrayList;
  • 适合读多写少的场景;
  • 读操作无锁;
  • 写操作则通过创建底层数组的新副本来实现,是一种读写分离的并发策略,阻塞写操作,读操作不会阻塞,实现读写分离;
  • 保证最终一致性;
  • 其底层数据结构也是数组;
  • 每次执行写操作都要将原容器拷贝一份,数据量大时,对内存压力较大,可能会引起频繁GC;二是无法保证实时性,Vector对于读写操作均加锁同步,可以保证读和写的强一致性;
  • CopyOnWriteArrayList默认容量是数组长度为1的Object类型数组;

定义

public class CopyOnWriteArrayList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable

成员属性

    // 使用可重入锁进行加锁,保证线程安全
    final transient ReentrantLock lock = new ReentrantLock();

    // 底层数据结构,注意这里用volatile修饰,确定了多线程情况下的可见性
    private transient volatile Object[] array;

    // getter
    final Object[] getArray() {
        return array;
    }
    // setter
    final void setArray(Object[] a) {
        array = a;
    }

构造方法

    public CopyOnWriteArrayList() {
    // 所有对array的操作都是通过setArray和getArray进行的
    setArray(new Object[0]);
}

 public CopyOnWriteArrayList(Collection<? extends E> c) {
    Object[] elements;
    // 如果c是CopyOnWriteArrayList则把数组直接进行赋值,注意这里是浅拷贝,两个集合公用一个数组
    if (c.getClass() == CopyOnWriteArrayList.class)
        elements = ((CopyOnWriteArrayList<?>)c).getArray();
    else {
        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);
}

get

get
    // 直接无锁访问数组下标获取数据
    public E get(int index) {
        return get(getArray(), index);
    }

    private E get(Object[] a, int index) {
     return (E) a[index];
    }

add

// 向list中获取元素
public boolean add(E e) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        Object[] elements = getArray();
        int len = elements.length;
        // 注意这里将数组长度加1
        Object[] newElements = Arrays.copyOf(elements, len + 1);
        // 新元素放在最后一位
        newElements[len] = e;
        setArray(newElements);
        return true;
    } finally {
        lock.unlock();
    }
}

// 更新指定下标的元素
    public E set(int index, E element) {
        // 获取公共锁
        final ReentrantLock lock = this.lock;
        // 加锁
        lock.lock();
        try {
            // 获取数组
            Object[] elements = getArray();
            // 获取数组插入位置的元素
            E oldValue = get(elements, index);
            // 当值不相等时进行更新
            if (oldValue != element) {
                int len = elements.length;
                // 拷贝数组
                Object[] newElements = Arrays.copyOf(elements, len);
                newElements[index] = element;
                // 赋值给数组
                setArray(newElements);
            } else {
                // Not quite a no-op; ensures volatile write semantics
                // 当值相同时,直接赋值
                setArray(elements);
            }
            // 返回原来的值
            return oldValue;
        } finally {
            // 解锁
            lock.unlock();
        }
    }

remove

// 删除指定下标的元素
    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();
        }
    }

函数接口

   public void forEach(Consumer<? super E> action) {
        if (action == null) throw new NullPointerException();
        Object[] elements = getArray();
        int len = elements.length;
        for (int i = 0; i < len; ++i) {
            @SuppressWarnings("unchecked") E e = (E) elements[i];
            action.accept(e);//遍历执行Consumer
        }
    }

    public boolean removeIf(Predicate<? super E> filter) {
        if (filter == null) throw new NullPointerException();
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            if (len != 0) {
                int newlen = 0;
                Object[] temp = new Object[len];
                for (int i = 0; i < len; ++i) {
                    @SuppressWarnings("unchecked") E e = (E) elements[i];
                    if (!filter.test(e))//验证Predicate
                        temp[newlen++] = e;
                }
                if (newlen != len) {
                    setArray(Arrays.copyOf(temp, newlen));
                    return true;
                }
            }
            return false;
        } finally {
            lock.unlock();
        }
    }

    public void replaceAll(UnaryOperator<E> operator) {
        if (operator == null) throw new NullPointerException();
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len);
            for (int i = 0; i < len; ++i) {
                @SuppressWarnings("unchecked") E e = (E) elements[i];
                newElements[i] = operator.apply(e);
            }
            setArray(newElements);
        } finally {
            lock.unlock();
        }
    }

    public void sort(Comparator<? super E> c) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            Object[] newElements = Arrays.copyOf(elements, elements.length);
            @SuppressWarnings("unchecked") E[] es = (E[])newElements;
            Arrays.sort(es, c);
            setArray(newElements);
        } finally {
            lock.unlock();
        }
    }

 

posted @ 2020-04-15 16:38  昕友软件开发  阅读(255)  评论(0编辑  收藏  举报
欢迎访问我的开源项目:xyIM企业即时通讯