CopyOnWriteArrayList
每个CopyOnwriteArrayList对象都存在一个volatile修饰的array数组对象来存放具体元素,使用独占锁ReentrantLock对CopyOnWriteArrayList的新增修改进行原子性操作保证,源码:
final transient ReentrantLock lock = new ReentrantLock();
private transient volatile Object[] array;
新增源码如下:
public boolean add(E e) {
final ReentrantLock lock = this.lock;//获取独占锁
lock.lock();//加锁,保证操作原子性
try {
Object[] elements = getArray();//获取array对象数组
int len = elements.length;
//复制array数组到新数组,添加元素到新数组
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);//使用新数组替换添加前的数组
return true;
} finally {
lock.unlock();//释放锁
}
}
修改及删除原理一样。
弱一致问题
public E get(int index) {
return get(getArray(), index);
}
final Object[] getArray() {
return array;
}
private E get(Object[] a, int index) {
return (E) a[index];
}
从上面的代码可以看出,在调用get(int index)方法时,要执行下面两个方法,三个操作并没有加锁进行同步,这三个方法操作的是该对象的array数组,假设在执行三个方法的途中进行新增、删除、修改操作后是使用新的数组替换原来的数组,但是这三个方法操作的还是原来的array数组,这就是写时复制策略产生的弱一致性问题。
弱一致性的迭代器
迭代器:
public Iterator<E> iterator() {
return new COWIterator<E>(getArray(), 0);
}
迭代器构建时也是直接使用getArray()获取数组,相当于构建了一份快照,原理如上,也会产生迭代遍历弱一致的效果。
CopyOnwriterArraySet
public class CopyOnWriteArraySet<E> extends AbstractSet<E>
implements java.io.Serializable {}
可以知道:
CopyOnWriteArraySet继承于AbstractSet,这就意味着它是一个集合
实际上,CopyOnWriteArraySet包含CopyOnWriteArrayList对象,它是通过CopyOnWriteArrayList实现的,而CopyOnWriteArrayList本质是个动态数组队列,所以CopyOnWriteArraySet相当于通过通过动态数组实现的“集合”!
CopyOnWriteArrayList中允许有重复的元素;但是,CopyOnWriteArraySet它不能有重复集合
因此,CopyOnWriteArrayList额外提供了addIfAbsent()和addAllAbsent()这两个添加元素的API,通过这些API来添加元素时,只有当元素不存在时才执行添加操作!
至于CopyOnWriteArraySet的“线程安全”机制,和CopyOnWriteArrayList一样,是通过volatile和互斥锁来实现的。