一、高效读取CopyOnWriteArrayList
由于读操作根本不会修改原有的数据,因此对于每次读取操作都进行加锁其实是一种资源浪费。 应该允许多个线程同时访问List的内部数据,毕竟是安全的。根据读写锁的思想,读与读之间不冲突,但是读操作会受到写操作的影响,当发生写操作时,读就必须等待,否则可能读到不一致的数据。同理,如果读操作正在进行,程序也不能进行写入。
1.1 CopyOnWriteArrayList
对于这个类,读取完全不加锁,并且写入也不会阻塞读取操作,只是写入和写入之间需要进行同步等待。
其实现原理。就是在写入操作时,进行一次自我复制。将修改的内容写入副本中。写完之后,再将修改完的副本替换原来的数据。这样可以保证写操作不会受影响。
1.2 源码分析
public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
private transient volatile Object[] array; //volatile关键字修饰,可见性
/**
* 读操作不加锁
*/
public E get(int index) {
return get(getArray(), index);
}
final Object[] getArray() {
return 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);//用新数组替换老数组。修改完成。数组为volatile修饰。
return true;
} finally {
lock.unlock();
}
}
}
参考
- 《实战java高并发程序设计》