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(); } }
关于作者:
王昕(QQ:475660)
在广州工作生活30余年。十多年开发经验,在Java、即时通讯、NoSQL、BPM、大数据等领域较有经验。
目前维护的开源产品:https://gitee.com/475660
目前维护的开源产品:https://gitee.com/475660