讀寫鎖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();
}
}
}