读写锁ReentrantReadWriteLock性质
一、性质
1、支持锁的降级,在写锁释放前降级为读锁
2、不支持锁的升级,由读锁升级为写锁将会失败
3、写锁支持ReentrantLock.newCondition,读锁不支持,将会抛出异常UnsupportedOperationException
锁的降级测试代码
System.out.println("Enter");
r.lock();
System.out.println("read lock ");
r.unlock();
w.lock();
System.out.println("write lock");
r.lock();
System.out.println("read lock");
w.unlock();
r.unlock();
System.out.println("Outer");
/*output:
Enter
read lock
write lock
read lock
Outer
*/
锁的升级测试代码
System.out.println("Enter");
r.lock();
System.out.println("read lock ");
w.lock();//将会一直阻塞
System.out.println("write lock");
w.unlock();
r.unlock();
System.out.println("Outer");
/*output:
Enter
read lock
程序一直阻塞
*/
二、使用场景
在读多写少的场景下,使用读写锁提高程序的并发性 (实例代码来源于jdk源码注释))
1、提供一个读写目录,在读数据时获取读锁,写数据时获取写锁。只有读线程访问时,可以同时支持多个读线程访问,以此提供程序的并发性。
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(); }
}
}
2、系统缓存的更新,演示了锁的升级和降级使用
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();
}
}
}