接口依赖图
ReentrantReadWriteLock的接口依赖图
概述
Java并发编程包提供了读写锁的实现,其维护了一对相关的锁 ,即 “读取锁”和“写入锁”,一个用于读取操作,另一个用于写入操作。
“读取锁”用于只读操作,它是“共享锁”,能同时被多个线程获取。
“写入锁”用于写入操作,它是“独占锁”,写入锁只能被一个线程锁获取。
所谓读写锁,是对访问资源共享锁和排斥锁,一般的重入性语义为 如果对资源加了写锁,其他线程无法再获得写锁与读锁,但是持有写锁的线程,可以对资源加读锁(锁降级);如果一个线程对资源加了读锁,其他线程可以继续加读锁。
读写锁ReadWriteLock是一个接口。ReentrantReadWriteLock是它的实现类,ReentrantReadWriteLock包括内部类ReadLock和WriteLock。
java.util.concurrent.locks.ReadWriteLock源码如下:
public interface ReadWriteLock {
//获取一个读锁
Lock readLock();
//获取一个写锁
Lock writeLock();
}
ReentrantReadWriteLock支持以下功能:
1)支持公平和非公平的获取锁的方式;
2)支持可重入。读线程在获取了读锁后还可以获取读锁;写线程在获取了写锁之后既可以再次获取写锁又可以获取读锁;
3)还允许从写入锁降级为读取锁,其实现方式是:先获取写入锁,然后获取读取锁,最后释放写入锁。但是,从读取锁升级到写入锁是不允许的;
4)读取锁和写入锁都支持锁获取期间的中断;
5)Condition支持。仅写入锁提供了一个 Conditon 实现;读取锁不支持 Conditon ,readLock().newCondition() 会抛出 UnsupportedOperationException。
java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock.newCondition()
public Condition newCondition() {
throw new UnsupportedOperationException();
}
java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock.newCondition()
public Condition newCondition() {
return sync.newCondition();
}
使用
示例一:利用重入来执行升级缓存后的锁降级
class CachedData {
Object data;
//保证状态可见性
volatile boolean cacheValid;
ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
void processCachedData() {
rwl.readLock().lock();
if (!cacheValid) {
// 在获取写锁前必须释放读锁
rwl.readLock().unlock();
rwl.writeLock().lock();
//再次检查其他线程是否已经抢到
if (!cacheValid) {
//获取数据
data = ...
cacheValid = true;
}
// 在释放写锁之前通过获取读锁来降级
rwl.readLock().lock();
//释放写锁,保持读锁
rwl.writeLock().unlock();
}
use(data);
rwl.readLock().unlock();
}
}
示例二:使用 ReentrantReadWriteLock 来提高 Collection 的并发性
在使用某些种类的 Collection 时,可以使用 ReentrantReadWriteLock 来提高并发性。通常,在预期 Collection很大,读取者线程访问它的次数多于写入者线程,并且 entail 操作的开销高于同步开销时,这很值得一试。例如,以下是一个使用 TreeMap 的类,预期它很大,并且能被同时访问。
class RWDictionary {
private final Map<String, Data> m = new TreeMap<String, Data>();
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock(); //读锁
private final Lock w = rwl.writeLock(); //写锁
public Data get(String key) {
r.lock();
try { return m.get(key); }
finally { r.unlock(); }
}
public String[] allKeys() {
r.lock();
try { return m.keySet().toArray(); }
finally { r.unlock(); }
}
public Data put(String key, Data value) {
w.lock();
try { return m.put(key, value); }
finally { w.unlock(); }
}
public void clear() {
w.lock();
try { m.clear(); }
finally { w.unlock(); }
}
}
参考文档:
1. https://www.cnblogs.com/zaizhoumo/p/7782941.html
2. https://blog.csdn.net/prestigeding/article/details/53286756
3. https://blog.csdn.net/qq924862077/article/details/70303821