2020-02-03 2.2.4 读写锁 ReadWriteLo
2020-02-03 本文已影响0人
FredWorks
本文是Java线程安全和并发编程知识总结的一部分。
2.2.4 读写锁
ReentrantLock实现的是一种标准的互斥锁,每次只允许一个线程获得锁操作。而现实中,大部分业务操作都是读操作多余写操作。只要确保多个线程可以读取到最新的数据,且期间不会有其他线程修改数据,那么实际上多个线程同时读,是不会引发业务上的冲突的。此时,并发性能会比RentrantLock更高。
实现这个意图的锁就是ReadWriteLock
及其实现ReentrantReadWriteLock
。
- 读写锁允许单独获取读锁和写锁。
- 读锁允许多个线程同时申请并获得,从而实现多线程读。
- 写锁只允许一个线程获得,从而确保只有一个线程在写。
需要说明的是:
- ReadWriteLock 并未说明读锁和写锁是否是可重入锁。但ReentrantReadWriteLock是可重入锁实现。
- ReadWriteLock 对锁获取插队问题没有规定。ReentrantReadWriteLock为公平锁时,不允许插队;为非公平锁时允许读锁插队到写锁而将写锁降级为读锁,但不允许写锁插队到读锁从而将读锁升级为写锁。
大体上而言,读写锁是否一定能提升性能?这个需要区分场景分析:
- 如果一个任务中,读操作远远大于写操作,那么读写锁性能提升是明显的。
- 如果一个任务中,读写操作的耗时大体相当,甚至写多余读,那么读写锁基本不会有什么性能提升。
需要注意的是:
- 使用读写锁的代码是否会发生脏写,并不由读写锁代码本身控制,而是由使用读写锁的业务代码决定。假如一个线程在执行读操作时,有另外一个线程执行写操作了,那么读线程可能会读取到脏数据的。
下面是一个封装普通ArrayList使其读并发写串行的例子:
/**
* @author xx
* 2020年2月3日 下午6:02:32 xx添加此方法
*/
public class ReadWriteLockArrayList<T> extends ArrayList<T> {
private static final long serialVersionUID = 5764776949955586441L;
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock readLock = this.lock.readLock();
private final Lock writeLock = this.lock.writeLock();
private ArrayList<T> list;
/**
* 构造函数
*/
public ReadWriteLockArrayList(int initialCapacity) {
this.list = new ArrayList<T>(initialCapacity);
}
/**
* 构造函数
*/
public ReadWriteLockArrayList() {
this.list = new ArrayList<T>();
}
/**
* 构造函数
*/
public ReadWriteLockArrayList(Collection<T> c) {
this.list = new ArrayList<T>(c);
}
/**
* 读操作,加读锁
* 参看父类中的注释 @see java.util.ArrayList#get(int)
* 2020年2月3日 下午6:02:32 xx添加此方法
*/
public T get(int index) {
this.readLock.lock();
try {
return this.list.get(index);
} finally {
this.readLock.unlock();
}
}
/**
* 写操作,加写锁
* 参看父类中的注释 @see java.util.ArrayList#add(E e)
* 2020年2月3日 下午6:02:32 xx添加此方法
* @param e
* @return
*/
public boolean add(T e) {
this.writeLock.lock();
try {
return this.list.add(e);
} finally {
this.writeLock.unlock();
}
}
/**
* 写操作,加写锁
* 参看父类中的注释 @see java.util.ArrayList#trimToSize()
* 2020年2月3日 下午6:02:32 xx添加此方法
*/
public void trimToSize() {
this.writeLock.lock();
try {
this.list.trimToSize();
} finally {
this.writeLock.unlock();
}
}
/*
* 其他操作类似上述行为
*/
}