CopyOnWriteArrayList介绍:
CopyOnWrite 简称COW,一种用于集合的并发访问的优化策略。
思路:对一个集合容器中进行写入(有关更改操作时,即添加,修改,删除),并不会直接将操作进行在原有的集合中,而是将原集合中的元素复制(Copy)到另一个新的集合容器中,然后在对新的数组进行操作,继而将引用指向新的集合容器。
这样的好处是保证了修改操作时集合容器的线程安全,并且在写入操作时,读取操作也是可以进行的。所以copyonwrite容器是对读写分离思想的一种实现。
CopyOnWriteArrayList相当于线程安全的ArrayList,内部存储结构采用Object[ ]数组,线程安全使用ReentrantLock实现,允许多个线程并发读取,但只能有一个线程进行写入操作。
部分源码的个人解析:
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.RandomAccess;
import java.util.concurrent.locks.ReentrantLock;
public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
// 定义了一个锁,即对写入(增加,删除,修改)使用的,
// 保护写入时线程安全,因为只有一把锁,所以有一个线程在进行写入操作时,
// 其他的写入操作也不能被其他线程使用
final transient ReentrantLock lock = new ReentrantLock();
private transient volatile Object[] array;
/**
* Gets the array. Non-private so as to also be accessible
* from CopyOnWriteArraySet class.
*/
final Object[] getArray() {
return array;
}
/**
* Sets the array.
*/
final void setArray(Object[] a) {
array = a;// 将集合引用指向新的集合
}
public CopyOnWriteArrayList() {
setArray(new Object[0]);
}
@SuppressWarnings("unchecked")
private E get(Object[] a, int index) {
return (E) a[index];
}
// get,并没有用Reentrantlock保护,
// 所以获得某个值是所有线程同时都可以访问
public E get(int index) {
return get(getArray(), index);
}
// set,用Reentrantlock保护,
// 所以同时有且只有一个线程可以访问
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);// 调用setArray方法将集合引用指向新的集合
} else {
// Not quite a no-op; ensures volatile write semantics
setArray(elements);// 值相同时直接将引用指向旧集合
}
return oldValue;// 返回更改前的值
} finally {// finally中逻辑的执行不受try块中逻辑影响,try块执行后,finally中逻辑必定执行
lock.unlock();// 释放锁
}
}
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();// 释放锁
}
}
public void add(int index, E element) {
final ReentrantLock lock = this.lock;
lock.lock();// 上锁
try {
// 得到旧数组及数据
Object[] elements = getArray();
int len = elements.length;
// 判断插入位置,如果大数组长度或者小于0,抛异常
if (index > len || index < 0)
throw new IndexOutOfBoundsException("Index: "+index+
", Size: "+len);
Object[] newElements;// 新数组
int numMoved = len - index;//计算插入位置
if (numMoved == 0)// 最后插入
newElements = Arrays.copyOf(elements, len + 1);// 将原数组赋值给新数组,位置不变,相当于add方法
else {
newElements = new Object[len + 1];// 新数组扩大容量
System.arraycopy(elements, 0, newElements, 0, index);// 从零开始将旧数组中的值赋值给新数组,赋值index位
System.arraycopy(elements, index, newElements, index + 1,// 将旧数组中从index位开始的值赋值给新数组且从index+1位开始,赋值numMoved位
numMoved);
}
newElements[index] = element;// element对新数组中的index位赋值
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;
if (numMoved == 0)// 判断位置
setArray(Arrays.copyOf(elements, len - 1));// 最后一位,就将前面的值直接赋值于新数组,并指向
else {
// 同add(int,E)添加中的操作
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();// 释放锁
}
}
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;// 删除到最后的位置
if (numMoved == 0)// 判断剩余是否为0
setArray(Arrays.copyOf(elements, newlen));// 最后一位,就将前面的值直接赋值于新数组,并指向
else {
// 将旧数组中的值导入新数组,同上面的其他方法
Object[] newElements = new Object[newlen];
System.arraycopy(elements, 0, newElements, 0, fromIndex);
System.arraycopy(elements, toIndex, newElements,
fromIndex, numMoved);
setArray(newElements);
}
} finally {
lock.unlock();// 释放锁
}
}
// 删除数组中C中的元素
public boolean removeAll(Collection<?> c) {
if (c == null) throw new NullPointerException();
final ReentrantLock lock = this.lock;
lock.lock();// 上锁
try {
// 得到旧数组
Object[] elements = getArray();
int len = elements.length;
// 长度是否为0
if (len != 0) {
// temp array holds those elements we know we want to keep
int newlen = 0;
Object[] temp = new Object[len];// 建立临时数组
for (int i = 0; i < len; ++i) {
Object element = elements[i];
if (!c.contains(element))// 遍历数组,查询有关元素是否存在
temp[newlen++] = element;//将值赋给临时数组
}
if (newlen != len) {// 如果不和原数组相同
setArray(Arrays.copyOf(temp, newlen));
return true;
}
}
return false;
} finally {
lock.unlock();// 释放锁
}
}
public void clear() {
final ReentrantLock lock = this.lock;
lock.lock();// 上锁
try {
setArray(new Object[0]);// 指向一个为0的新数组
} finally {
lock.unlock();// 释放锁
}
}
// 向数组中添加
public boolean addAll(Collection<? extends E> c) {
Object[] cs = (c.getClass() == CopyOnWriteArrayList.class) ?
((CopyOnWriteArrayList<?>)c).getArray() : c.toArray();// 得到传入数据
if (cs.length == 0)// 判断传入数量
return false;
final ReentrantLock lock = this.lock;
lock.lock();// 上锁
try {
// 旧数据
Object[] elements = getArray();
int len = elements.length;
// 判断旧数据长度,传入数组类型
if (len == 0 && cs.getClass() == Object[].class)
setArray(cs);
else {
// 扩容至len+cs,并赋值
Object[] newElements = Arrays.copyOf(elements, len + cs.length);
System.arraycopy(cs, 0, newElements, len, cs.length);
setArray(newElements);
}
return true;
} 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")// 抑制unchecked类型警告
E[] es = (E[])newElements;// 强制类型转换
Arrays.sort(es, c);// 调用Arrays的排序方法
setArray(newElements);
} finally {
lock.unlock();// 释放锁
}
}
public boolean equals(Object o) {
// 判断地址
if (o == this)
return true;
// 判断类型是否相同
if (!(o instanceof List))
return false;
// 创建临时集合和遍历器
List<?> list = (List<?>)(o);
Iterator<?> it = list.iterator();
// 得到旧
Object[] elements = getArray();
int len = elements.length;
for (int i = 0; i < len; ++i)// 循环比较每一个值
if (!it.hasNext() || !eq(elements[i], it.next()))//判断是否有下一个值和是否相同
return false;
if (it.hasNext())// 传入集合有下一个值
return false;
return true;
}
// 计算hash值
public int hashCode() {
int hashCode = 1;
Object[] elements = getArray();
int len = elements.length;
// 循环遍历每一个元素
for (int i = 0; i < len; ++i) {
Object obj = elements[i];
hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());// 新的hash值计算方式
}
return hashCode;
}
}