CopyOnWirteList主要用于的高并发的场景为读多写少的场景,下面来分析为什么它在高并发下读取的速度快。
首先看基础结构
public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
可以看出继承了list,以及三个标识接口
属性分析
/** The lock protecting all mutators */ 1. final transient ReentrantLock lock = new ReentrantLock(); 利用锁解决并发修改问题 2./** The array, accessed only via getArray/setArray. */ private transient volatile Object[] array;
数组实现list功能,volatile关键字保证了多线性读写情况下,修改的可见性
主要构造方法
主要方法分析:
读方法,读方法是未带锁的,可以看出当前读的时间复杂度未1,可见读的性能是非常高的
/**
* {@inheritDoc} * * @throws IndexOutOfBoundsException {@inheritDoc} */ public E get(int index) { return get(getArray(), index); }
增删修改方法,
这三种方法主要的是利用非公平锁保证数据安全性,修改时不选择在原数组中修改,选择的copy一份副本,然后修改数据,然后更新属性array为当前数据未修改后的数据,这样保证了其他读的线程在执行迭代等过程中不会出错。
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(); } }
/** * Appends the specified element to the end of this list. * * @param e element to be appended to this list * @return {@code true} (as specified by {@link Collection#add}) */ 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(); } }
/** * Removes the element at the specified position in this list. * Shifts any subsequent elements to the left (subtracts one from their * indices). Returns the element that was removed from the list. * * @throws IndexOutOfBoundsException {@inheritDoc} */ 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(); } }