Java併發程式設計-讀寫鎖
讀寫鎖既是一個排他鎖也是一個共享鎖,讀鎖是共享鎖,寫鎖是排他鎖。讀操作可以共存,讀操作和寫操作互斥,寫操作和寫操作之間互斥。下面是一個使用例子:
public class Demo {
private Map<String, Object> map = new HashMap<>();
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private Lock readLock = readWriteLock.readLock();
private Lock writeLock = readWriteLock.writeLock();
public Object get(String key) {
readLock.lock();
try {
return map.get(key);
} finally {
readLock.unlock();
}
}
public void set(String key, Object value) {
writeLock.lock();
try {
map.set(key, value);
} finally {
writeLock.unlock();
}
}
}
2.讀寫鎖原理
讀寫鎖需要儲存三個狀態,寫鎖重入的次數,讀鎖的個數,每個讀鎖重入的次數。記錄寫鎖和讀鎖重入的次數是為了實現鎖的可重入,記錄讀鎖的個數是為了在沒有執行緒持有讀鎖時,寫執行緒能進行寫操作。
3.鎖降級
鎖降級是指鎖降級為讀鎖。在寫鎖沒有釋放的時候,獲取到讀鎖,再釋放寫鎖。
我們先來看一個會引起問題的加鎖方式。
public class Demo {
private Map<String, Object> map = new HashMap<>();
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private Lock readLock = readWriteLock.readLock();
private Lock writeLock = readWriteLock.writeLock();
private boolean isUpdate;
public void readWrite() {
readLock.lock(); // 保證可以isUpdate可以拿到最新值
if (isUpdate) {
readLock.unlock();
writeLock.lock(); // 若干個寫執行緒阻塞在這一行
map.put("a","b");
writeLock.unlock();// 寫執行緒釋放鎖
}
Object object = map.get("a");// 讀執行緒讀取值
}
}
當寫執行緒釋放鎖,其他寫執行緒競爭到鎖後,讀執行緒此時讀取到的可能是髒值。
鎖降級方式加鎖:
public class Demo2 {
private Map<String, Object> map = new HashMap<>();
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private Lock readLock = readWriteLock.readLock();
private Lock writeLock = readWriteLock.writeLock();
private boolean isUpdate;
public void readWrite() {
readLock.lock(); // 保證可以isUpdate可以拿到最新值
if (isUpdate) {
readLock.unlock();
writeLock.lock();
map.put("a","b");
readLock.lock();
writeLock.unlock();
}
Object object = map.get("a");readLock.unlock();
}
}
在釋放寫鎖之前獲取讀鎖,此時其他執行緒在讀執行緒釋放讀鎖之前無法進行寫操作,進而保證了執行緒安全性。