目录
add(int index, E element)在指定下标添加元素
removeRange(int fromIndex, int toIndex)删除指定范围的元素
addAll(int index, Collection c)在指定位置批量添加元素
CopyOnWriteArrayList是一种线程安全的集合,通过ReentrantLock来实现集合的安全性。当我们对集合进行写入操作时,并不会直接在集合中写入,而是先将当前的集合复制,复制出一个新的集合,在新的集合中进行写入操作,写入 完成后,将原集合的引用指向新的集合。
CopyOnWriteArrayList的设计思想是读写分离,在保证写入操作的安全性时,也不会影响并发读取操作。它的内部使用Object[]数组,允许多线程并发读取,但只有一个线程可以进行写入操作。
- //默认的构造方法,数组初始化
- public CopyOnWriteArrayList() {
- setArray(new Object[0]);
- }
- // 有参构造方法
- public CopyOnWriteArrayList(Collection extends E> c) {
- Object[] elements;
- // copy的集合与当前集合是同一个Class对象
- if (c.getClass() == CopyOnWriteArrayList.class)
- // 将当前集合强转为CopyOnWriteArrayList并转为数组,存入elements中
- elements = ((CopyOnWriteArrayList>)c).getArray();
- else {
- // 直接将当前集合c赋给elements
- elements = c.toArray();
- // c.toArray might (incorrectly) not return Object[] (see 6260652)
- // 数组类型不是Object[]类型,对数组进行复制操作
- if (elements.getClass() != Object[].class)
- elements = Arrays.copyOf(elements, elements.length, Object[].class);
- }
- setArray(elements);
- }
- // 修改指定下标的值
- 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();
- }
- }
- // 添加元素至集合尾部
- 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 void add(int index, E element) {
- final ReentrantLock lock = this.lock;
- // 加锁
- lock.lock();
- try {
- // 得到原数组
- Object[] elements = getArray();
- int len = elements.length;
- // 判断下标位置是否合理,不合理抛异常
- if (index > len || index < 0)
- throw new IndexOutOfBoundsException("Index: "+index+
- ", Size: "+len);
- Object[] newElements;
-
- int numMoved = len - index;
- // 添加的元素的下标是尾下标
- if (numMoved == 0)
- // 复制原数组,长度加+1
- newElements = Arrays.copyOf(elements, len + 1);
- else {
- // 创建一个新数组,新数组长度=原数组长度+1
- newElements = new Object[len + 1];
- // 分别复制要添加的位置的前后的数组
- System.arraycopy(elements, 0, newElements, 0, index);
- System.arraycopy(elements, index, newElements, index + 1,
- numMoved);
- }
- // 将要添加的元素加到新数组的空位置
- newElements[index] = element;
- setArray(newElements);
- } finally {
- // 释放锁
- lock.unlock();
- }
- }
- // 删除指定下标的元素
- 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;
- // 如果=0说明删除的是最后一个元素
- if (numMoved == 0)
- // 复制原数组长度-1
- setArray(Arrays.copyOf(elements, len - 1));
- else {
- // 创建数组,长度为原数组-1
- Object[] newElements = new Object[len - 1];
- // 该操作与add(int index, E element)方法同理
- System.arraycopy(elements, 0, newElements, 0, index);
- System.arraycopy(elements, index + 1, newElements, index,
- numMoved);
- setArray(newElements);
- }
- return oldValue;
- } finally {
- // 解锁
- lock.unlock();
- }
- }
- // 删除指定范围的元素
- void removeRange(int fromIndex, int toIndex) {
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
- Object[] elements = getArray();
- int len = elements.length;
-
- // 判断下标位置是否合理,不合理抛异常
- if (fromIndex < 0 || toIndex > len || toIndex < fromIndex)
- throw new IndexOutOfBoundsException();
-
- // 计算新数组长度
- int newlen = len - (toIndex - fromIndex);
- // 获取结束下标的位置
- int numMoved = len - toIndex;
- // =0 ,复制原数组从0到newlen位置
- if (numMoved == 0)
-
- setArray(Arrays.copyOf(elements, newlen));
- else {
- // 新建一个数组,长度为newlen的
- Object[] newElements = new Object[newlen];
- // 该操作与add(int index, E element)方法同理
- System.arraycopy(elements, 0, newElements, 0, fromIndex);
- System.arraycopy(elements, toIndex, newElements, fromIndex, numMoved);
- setArray(newElements);
- }
- } finally {
- lock.unlock();
- }
- }
- // 清空集合中元素
- public void clear() {
- final ReentrantLock lock = this.lock;
- // 加锁
- lock.lock();
- try {
- // 数组初始化
- setArray(new Object[0]);
- } finally {
- lock.unlock();
- }
- }
- // 在指定位置批量添加元素
- public boolean addAll(int index, Collection extends E> c) {
- // 将集合c转换为数组并赋值给cs
- Object[] cs = c.toArray();
- final ReentrantLock lock = this.lock;
- lock.lock();
- try {
- // 获得原数组
- Object[] elements = getArray();
- //获取原数组的长度
- int len = elements.length;
- // 判断下标位置是否合理,不合理抛异常
- if (index > len || index < 0)
- throw new IndexOutOfBoundsException("Index: "+index+
- ", Size: "+len);
- // 如果集合c为空,则直接返回false
- if (cs.length == 0)
- return false;
- int numMoved = len - index;
- Object[] newElements;
- // 如果numMoved等于0,则代表在原集合末尾添加
- if (numMoved == 0)
- // 复制原集合,个数为原集合元素个数加要添加的元素个数
- newElements = Arrays.copyOf(elements, len + cs.length);
- else {
- // 创建新集合
- newElements = new Object[len + cs.length];
- // 该操作与add(int index, E element)方法同理
- System.arraycopy(elements, 0, newElements, 0, index);
- System.arraycopy(elements, index,
- newElements, index + cs.length,
- numMoved);
- }
- // 复制数组至新数组
- System.arraycopy(cs, 0, newElements, index, cs.length);
- setArray(newElements);
- return true;
- } finally {
- lock.unlock();
- }
- }