CopyOnWriteArrayList:Java集合中的读写分离

提到读写分离,大家可能首先会想到MySQL的读写分离,也就是在master节点上进行数据库写操作,在slave节点上进行数据库读操作,用这样的手段来提升数据库的性能、稳定性、高并发。其实,在java编程语言中,有一个集合类也贯彻了读写分离的思想,它就是:CopyOnWriteArrayList (另外一个类CopyOnWriteArraySet与此类似)。

一、CopyOnWriteArrayList总体介绍

我们先来看一下此集合类的层级结构:
CopyOnWriteArrayList:Java集合中的读写分离
CopyOnWriteArrayList类实现了List接口,是ArrayList一种线程安全的变体,所有的可变操作(增删改等),都是通过复制底层数组来进行的。官方文档说明如下:

A thread-safe variant of ArrayList in which all mutative operations (add, set, and so on) are implemented by making a fresh copy of the underlying array.

二、CopyOnWriteArrayList实现原理

通过源码看一下类的底层实现原理,以下是类变量:

//可重入锁,对所有可变操作加锁
final transient ReentrantLock lock = new ReentrantLock();
//存储数据的数组,保证可见性。只有getArray和setArray方法可以访问
private transient volatile Object[] array;

向容器中添加元素的源码如下:

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();
        	}
        }

可以看出,在开始添加元素前,先进行加锁操作,然后获取当前容器底层的数组数据,通过Arrays.copyOf方法复制到一个新的数组中,添加元素后把新的数组赋值给容器底层的数组,最后释放锁。其它的可变操作,比如删除、元素替换等,实现机制是相同的,都是通过复制一个新的数组来进行的。

读取操作比较简单,直接从数组中获取数据,没有进行加锁:

public E get(int index) {   
	return get(getArray(), index);
}

因为写操作总是复制底层数组来进行运算,而读操作直接读取数组中数据,所以这是一种读写分离的形式。当然,因为每次可变操作都要进行数组的复制,这个代价是相当高的,所以CopyOnWriteArrayList比较适合读多写少的场合,比如商品品类,省市区等地址信息等。

三、与ArrayList的对比

既然CopyOnWriteArrayList是ArrayList的变体,那么它们肯定有区别,下面的表格从多个角度对比了两者不一样的地方:

CopyOnWriteArrayList ArrayList
线程安全 线程不安全
效率高 效率低
一个线程在遍历容器的时候,其它线程可以对容器进行修改,因为是在一个新的数组上操作,所以CopyOnWriteArrayList不会抛出ConcurrentModificationException 一个线程在遍历容器的时候,如果其它线程对容器进行修改,那么会抛出ConcurrentModificationException
fast-safe fast-fail
属于 java.util.concurrent包 属于java.util包
java 1.5 引进 fast-fail
fast-safe java 1.2 引进

参考资料:
http://www.benchresources.net/copyonwritearraylist-vs-arraylist-in-java/
http://www.makeinjava.com/copyonwritearraylist-concurrent-collection-java-example/

欢迎关注微信公众号,获取更多信息。
CopyOnWriteArrayList:Java集合中的读写分离