核心概念
- 讀鎖(共享鎖):多線程可同時持有,讀讀不互斥;
- 寫鎖(排他鎖):同一時間僅一線程持有,讀寫、寫寫互斥;
- 鎖降級:寫鎖 → 讀鎖 支持,讀鎖 → 寫鎖 不支持(需釋放讀鎖再獲取寫鎖)。
原始代碼 Bug 修正
// 原代碼 finally 中寫鎖調用了 w.lock(),應為 w.unlock()
finally { w.unlock(); }
完整驗證Demo
// 共享資源
class DataStore {
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock(), w = rwl.writeLock();
private String data = "init";
public void read() {
r.lock();
try { Thread.sleep(1000); System.out.println(Thread.currentThread().getName() + " read: " + data); }
catch (InterruptedException e) { Thread.currentThread().interrupt(); }
finally { r.unlock(); }
}
public void write(String v) {
w.lock();
try { Thread.sleep(3000); data = v; System.out.println(Thread.currentThread().getName() + " wrote: " + v); }
catch (InterruptedException e) { Thread.currentThread().interrupt(); }
finally { w.unlock(); }
}
}
// 讀任務
class ReadTask implements Runnable {
private final DataStore store;
ReadTask(DataStore s) { store = s; }
public void run() { store.read(); }
}
// 寫任務
class WriteTask implements Runnable {
private final DataStore store; private final String val;
WriteTask(DataStore s, String v) { store = s; val = v; }
public void run() { store.write(val); }
}
// 主程序
public class RWLockDemo {
public static void main(String[] args) {
DataStore store = new DataStore();
// 2 寫線程(互斥)、4 讀線程(並發)
new Thread(new WriteTask(store, "v1"), "W-1").start();
new Thread(new WriteTask(store, "v2"), "W-2").start();
for (int i = 1; i <= 4; i++)
new Thread(new ReadTask(store), "R-" + i).start();
}
}
預期輸出現象
- 兩寫線程**串行**(間隔 ~3s);
- 四讀線程**幾乎同時**打印(讀鎖共享);
- 寫期間讀線程阻塞,讀期間寫線程阻塞。
最佳實踐提醒
- 業務讀多寫少場景優先考慮
ReentrantReadWriteLock;
- 避免在鎖內調用耗時 IO / 睡眠,縮小臨界區;
- Java 8+ 可考慮
StampedLock(樂觀讀、無條件遞歸),性能更優但 API 較複雜。