并发操作
并发操作之——ReentrantReadWriteLock.
并发操作之——ReentrantReadWriteLock
并发操作之——ReentrantReadWriteLock
高并发环境下多线程加锁的问题。
一、ReentrantReadWriteLock
1、读写锁
读写锁接口readWriteLock接口的一种实现,实现了读写分离。
2、公平和非公平锁
支持公平和非公平锁,底层也是AQS实现。
3、锁降级
允许从写锁降级为读锁
流程: 先获取写锁,然后获取读锁,最后释放写锁;但不能从读锁升级到写锁。
4、重入
读锁后还可以获取读锁,获取写锁之后可以获取写锁和读锁。
5、核心
读锁是共享的,写锁是独占的。读和读之间不会互斥,读和写、写和读之间才会互斥,主要是提升了读写的性能。
二、ReentrantReadWriteLock应用场景
应用场景: 读多写少,比如设计一个缓存组件 或 提高Collection的并发性
源码本身提供案例,示例一:用ReenTrantReadWriteLock做读写锁分离操作
class CachedData {
Object data;
volatile boolean cacheValid;
final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
void processCachedData() {
rwl.readLock().lock();
if (!cacheValid) {
// Must release read lock before acquiring write lock
rwl.readLock().unlock();
rwl.writeLock().lock();
try {
// Recheck state because another thread might have
// acquired write lock and changed state before we did.
if (!cacheValid) {
data = ...
cacheValid = true;
}
// Downgrade by acquiring read lock before releasing write lock
rwl.readLock().lock();
} finally {
rwl.writeLock().unlock(); // Unlock write, still hold read
}
}
try {
use(data);
} finally {
rwl.readLock().unlock();
}
}
}}
源码本身提供案例,示例二:实现一个线程安全的map
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(); }
}
}}
三、ReentrantReadWriteLock和ReenTrantLock的区别
总结
最主要的区别是ReenTrantReadWriteLock对比ReenTrantLock可以实现读写锁分离,再就是ReenTrantReadWriteLock特殊的重入锁机制。