线程安全集合——CopyOnWriteArrayList
文章目录
- 前言
- 一、CopyOnWriteArrayList是什么?
- 二、如何使用
- 三、底层方法实现
- 3.1 add()
- 3.2 remove()
- 3.3 set()
- 3.4 get()
前言
一、CopyOnWriteArrayList是什么?
CopyOnWriteArrayList是一个线程安全的集合,是List接口的实现类。它是用ReentrantLock来保证线程安全的,其用法和List接口下其他的实现类相差不大。
二、如何使用
public static void main(String[] args) {// List接口下线程安全的集合CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();// 修改操作(加锁)// 1. 添加list.add("a");list.add("b");list.add("c");// 2. 删除list.remove(0);// 3. 修改list.set(1, "d");// 查询操作(不加锁)String s = list.get(1);System.out.println(s);System.out.println(list);}
三、底层方法实现
3.1 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();}}
实现概述: 加锁后复制原数组并扩容1位,在新数组末尾添加元素,最后替换底层数组引用。体现了"写时复制"的核心思想。
3.2 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();}}
实现复述:加锁后创建缩容1位的新数组,分两种情况处理:如果是最后一位元素直接截断,否则删除中间元素并分两段复制到新数组中。
3.3 set()
源代码如下:
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 semanticssetArray(elements);}return oldValue;} finally {lock.unlock();}}
实现概述: 加锁后先比较新旧值,如果不同则复制整个数组并修改指定位置的元素,相同时也要调用setArray()确保数组中的内容是最新的。
3.4 get()
源代码如下:
private E get(Object[] a, int index) {return (E) a[index];
}
实现概述: 无锁操作,直接从volatile数组中获取指定位置的元素,保证了读操作的高性能。