CopyOnWriteArrayList 的优点:CopyOnWriteArrayList 经常被用于“读多写少”的并发场景,是因为 CopyOnWriteArrayList 无需任何同步措施,大大增强了读的性能。在 Java 中遍历非线程安全的List(ArrayList 和 LinkedList)时,若中途有别的线程对 List 容器进行修改,那么会抛出 ConcurrentModificationException 异常。CopyOnWriteArrayList 由于其"读写分离",遍历和修改操作分别作用在不同的 List 容器,所以在使用迭代器遍历的时候,则不会抛出异常。
CopyOnWriteArrayList 的缺点:第一个缺点是 CopyOnWriteArrayList 每次执行写操作都会将原容器拷贝一份,数据量大的时候,内存会存在较大的压力,可能会引起频繁 Full GC,比如这些对象占用的内存 200M 左右,那么再写入 100M 数据进去,内存就会多占用 300M。第二个缺点是 CopyOnWriteArrayList 由于实现的原因,写和读分别作用在不同新老容器上,在写操作执行过程中,读不会阻塞,但读取到的却是老容器的数据。
package java.util.concurrent;publicclassCopyOnWriteArrayList<E>implementsList<E>, RandomAccess, Cloneable, java.io.Serializable {
//The lock protecting all mutators.finaltransient ReentrantLock lock =newReentrantLock();//The array, accessed only via getArray/setArray.privatetransientvolatile Object[] array;//Gets the array. Non-private so as to also be accessible from CopyOnWriteArraySet class.final Object[]getArray(){
return array;}//Sets the array.finalvoidsetArray(Object[] a){
array = a;}//Creates an empty list.publicCopyOnWriteArrayList(){
setArray(newObject[0]);}//CopyOnWriteArrayList的add()方法是先把原容器进行copy,然后在新的副本上进行“写操作”,最后再切换引用,在此过程中是加了锁的.//Appends the specified element to the end of this list.publicbooleanadd(E e){
//ReentrantLock加锁保证线程安全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);returntrue;}finally{
//释放锁
lock