CopyOnWriteArrayList
在没有JUC前,线程安全的List我们可以用Collections.synchronizedList()
.现在多了一种选择,就是今天所说的CopyOnWriteArrayList
.
CopyOnWriteArrayList
采用的是写时复制
策略,即真正需要更新列表的时候,会从原有的数组上进行一个复制,然后在这个复制出来的列表上做更新操作.
类图
从类图我们可以知道,CopyOnWriteArrayList有2个元素,lock是用来保证只有一个线程可以对当前对象进行修改的锁,array则存放了列表中的数据.
为什么CopyOnWriteArrayList能保证线程安全?
构造函数
- java.util.concurrent.CopyOnWriteArrayList#CopyOnWriteArrayList(java.util.Collection<? extends E>)
/**
* Creates a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection of initially held elements
* @throws NullPointerException if the specified collection is null
*/
public CopyOnWriteArrayList(Collection<? extends E> c) {
Object[] elements;
if (c.getClass() == CopyOnWriteArrayList.class)
elements = ((CopyOnWriteArrayList<?>)c).getArray();
else {
elements = c.toArray();
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elements.getClass() != Object[].class)
elements = Arrays.copyOf(elements, elements.length, Object[].class);
}
setArray(elements);
}
将传入的集合转换成数组,然后赋值或者复制给array变量.这里从注释上我们可以知道,CopyOnWriteArrayList是保证有序的.
add
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#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.添加元素的时候,先获取独占锁,保证互斥性.
2.成功获取锁的线程,对代码块进行上锁,然后获取原来列表的元素数组,复制一份到元素大小为length+1的数组中,然后在尾部添加需要被add的元素.
3.释放锁
这里我们可以总结一下:copyOnWriteArrayList对于这种增删的操作,它是能保证线程安全的,其次,每次做增删,都需要对原数组进行复制操作赋值到新的数组上,这正是copy-on-wrtie
的思想体现.
CopyOnWriteArrayList的弱一致性
在读操作的时候,如果数组正在进行复制行为,那么此时读到的是旧数组的数据,JDK只能保证数据的最终一致性,无法保证实时一致性,所以CopyOnWriteArrayList
比较适合读多写少的场景。
具体可以看JDK的注释介绍:
Memory consistency effects: As with other concurrent collections, actions in a thread prior to placing an object into a CopyOnWriteArrayList happen-before actions subsequent to the access or removal of that element from the CopyOnWriteArrayList in another thread.
内存一致性影响:与其他并发集合一样,在将对象放入CopyOnWriteArrayList之前,线程中的操作发生在另一个线程中访问或从CopyOnWriteArray中删除该元素之后的操作之前。