CopyOnWrite(COW):是一种用于集合的并发访问的。基本思想是:当我们往集合中写入(修改,删除,添加)元素时,并不会直接在集合中写入,而是先将集合复制出来,然后写入操作在新复制的集合中操作,完成写入操作后,再将旧集合的引用指向新集合。这种做法的好处:即实现了写入操作时线程安全,又可以在写入同时对集合进行读取操作。
CopyOnWriteArrayList类部分源码阅读:
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]);
}
//从数组a中获取index位置的元素值
@SuppressWarnings("unchecked")
private E get(Object[] a, int index) {
return (E) a[index];
}
//获取元素
public E get(int index) {
return get(getArray(), index);
}
//在下标index位置修改元素的值为element
public E set(int index, E element) {
//给当前锁重新指向一个引用
final ReentrantLock lock = this.lock;
//加锁
lock.lock();
try {
//得到数组元素
Object[] elements = getArray();
//获取下标index位置的元素element,并将值赋给oldValue
E oldValue = get(elements, index);
//判断获取的oldValue的值是否和要修改的元素element的值一致
//如果不一致,就修改
if (oldValue != element) {
//获取数组的长度
int len = elements.length;
//将数组复制,赋给变量newElement
Object[] newElements = Arrays.copyOf(elements, len);
//将新数组中下标为index位置修改为元素element
newElements[index] = element;
//将旧数组的引用指向新数组
setArray(newElements);
} else {
// Not quite a no-op; ensures volatile write semantics
setArray(elements);
}
return oldValue;
} finally {
//释放锁
lock.unlock();
}
}
//添加元素e
public boolean add(E e) {
//给当前锁重新指向一个引用
final ReentrantLock lock = this.lock;
//加锁
lock.lock();
try {
//得到数组元素
Object[] elements = getArray();
//获取数组的长度
int len = elements.length;
//将数组复制,赋给变量newElement(len+1是因为要添加一个元素)
Object[] newElements = Arrays.copyOf(elements, len + 1);
//将数组末尾的位置添加进元素e
newElements[len] = e;
//将旧数组的引用指向新数组
setArray(newElements);
return true;
} finally {
//释放锁
lock.unlock();
}
}
//在index位置添加元素element
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)
//复制数组元素,长度为len+1,将e放入数组末尾
newElements = Arrays.copyOf(elements, len + 1);
else {
//创建一个数组,长度为len+1
newElements = new Object[len + 1];
//复制旧数组中下标在index前的元素
System.arraycopy(elements, 0, newElements, 0, index);
//复制旧数组中下标在index后的元素
System.arraycopy(elements, index, newElements, index + 1,
numMoved);
}
//在index位置上添加element元素
newElements[index] = element;
//将旧数组的引用指向新数组
setArray(newElements);
} finally {
lock.unlock();
}
}
//删除index位置的元素
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);
//数组长度-删除的下标-1
int numMoved = len - index - 1;
//判断要删除的元素是否为最后一个元素
if (numMoved == 0)
//如果是,不用复制最后一个元素
setArray(Arrays.copyOf(elements, len - 1));
else {
//创建新数组,长度为len-1
Object[] newElements = new Object[len - 1];
//复制旧数组中下标在index前的元素
System.arraycopy(elements, 0, newElements, 0, index);
//复制旧数组中下标在index后(不包括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
if (numMoved == 0)
//复制数组elements中的元素,长度为newLen,引用指向复制后的数组
setArray(Arrays.copyOf(elements, newlen));
else {
//如果移动的位置不为0
Object[] newElements = new Object[newlen];
//复制数组elements中从0开始的元素,到新数组中从0开始到删除起始下标的位置
System.arraycopy(elements, 0, newElements, 0, fromIndex);
//复制删除结束下标位置后的元素到新数组中
System.arraycopy(elements, toIndex, newElements,
fromIndex, numMoved);
//旧数组引用指向新数组
setArray(newElements);
}
} finally {
lock.unlock();
}
}
//删除当前集合与指定集合的相同元素
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;
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) {
//获取数组中位置i的元素
Object element = elements[i];
//判断c集合中是否包含当前元素
if (!c.contains(element))
//不包含,将当前元素放入新集合中
temp[newlen++] = element;
}
//如果新集合的长度不等于旧集合的长度
if (newlen != len) {
//使用Arrays工具类中的copy()复制数组,并将引用指向复制后的数组
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]);
} finally {
lock.unlock();
}
}
//将c集合中的元素添加到当前集合
public boolean addAll(Collection<? extends E> c) {
//判断两个集合的类型是否一致
//判断集合的类型是否是CopyOnWriteArrayList
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;
//判断原有长度是否为0,判断是否为Object[]类型
//长度为0,类型一样,说明原有集合列表为空
if (len == 0 && cs.getClass() == Object[].class)
//将引用指向cs集合
setArray(cs);
else {
//复制旧数组中的元素,长度为旧数组的长度和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") E[] es = (E[])newElements;
//使用Arrays工具类中的sort()方法进行排序
Arrays.sort(es, c);
setArray(newElements);
} finally {
lock.unlock();
}
}
//比较内容
public boolean equals(Object o) {
//判断当前的值和传入的值
if (o == this)
//如果相等,返回true
return true;
//判断传入的类型是否是List集合
if (!(o instanceof List))
return false;
//将当前元素转型为集合
List<?> list = (List<?>)(o);
//调用iterator():迭代器
Iterator<?> it = list.iterator();
Object[] elements = getArray();
int len = elements.length;
//遍历数组
for (int i = 0; i < len; ++i)
//如果集合中没有下一个元素或者调用eq()内容不相同
if (!it.hasNext() || !eq(ele ments[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];
//判断obj是否等于0 ,如果为0,返回0+31*1
//否则调用Object类的hashCode()方法计算此元素的hash值
hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
}
return hashCode;
}
}