首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 並發編程核心:ReentrantLock 與 ReadWriteLock 深度解析

     編輯:Java 相關知識

背景:從 synchronized 到顯式鎖

Java 5.0 前僅有 synchronized(內置鎖)和 volatile。JDK 5.0 引入 java.util.concurrent.locks.Lock 接口及其核心實現 ReentrantLock,提供更精細的鎖控制能力。

Lock 接口核心方法

public interface Lock {
    void lock();                    // 阻塞獲取鎖
    void lockInterruptibly() throws InterruptedException; // 可中斷獲取
    boolean tryLock();              // 非阻塞嘗試獲取
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException; // 超時獲取
    void unlock();                  // 釋放鎖
    Condition newCondition();       // 關聯條件變量
}

ReentrantLock 關鍵特性

特性說明對應方法
可重入同一線程可多次獲取鎖,需同次數釋放內部實現
公平/非公平構造函數 new ReentrantLock(true) 選擇公平鎖(FIFO),預設非公平(吞吐率高)構造函數
輪詢獲取嘗試獲取鎖,失敗立即返回,避免死鎖tryLock()
定時獲取在指定時間內嘗試獲取,超時返回tryLock(time, unit)
可中斷獲取鎖過程中可響應中斷,拋出 InterruptedExceptionlockInterruptibly()
條件變量一個鎖可關聯多個 Condition,實現精細線程協作newCondition()

標準使用模板

Lock lock = new ReentrantLock();
lock.lock();
try {
    // 臨界區操作
} finally {
    lock.unlock(); // 必須在 finally 中釋放,防止死鎖
}

公平鎖 vs 非公平鎖性能權衡

  • 非公平鎖(預設):線程嘗試獲取鎖時,若鎖空閒則直接搶佔,即使有排隊線程。減少線程切換開銷,吞吐率高。
  • 公平鎖:嚴格按請求順序授予鎖。適用於對公平性敏感場景,但頻繁阻塞/喚醒導致性能下降。
  • 建議:除非有明確公平性需求,優先使用非公平鎖。

ReadWriteLock 讀寫鎖

針對「讀多寫少」場景優化:允許多線程並發讀,寫操作獨佔。

public interface ReadWriteLock {
    Lock readLock();  // 共享鎖
    Lock writeLock(); // 排他鎖
}

ReentrantReadWriteLock 實現要點

  • 釋放優先:寫鎖釋放後,優先喚醒等待的寫線程(防止寫飢餓),或配置讀線程插隊。
  • 重入性:讀鎖、寫鎖均可重入;持有寫鎖可降級為讀鎖,持有讀鎖不可升級為寫鎖(防止死鎖)。
  • 公平性選項:構造函數同 ReentrantLock。

實戰範例:線程安全 Map

public class ReadWriteMap<K, V> {
    private final Map<K, V> map = new HashMap<>();
    private final ReadWriteLock lock = new ReentrantReadWriteLock();
    private final Lock r = lock.readLock();
    private final Lock w = lock.writeLock();

    public V get(K key) {
        r.lock();
        try { return map.get(key); }
        finally { r.unlock(); }
    }

    public void put(K key, V value) {
        w.lock();
        try { map.put(key, value); }
        finally { w.unlock(); }
    }
}

進階應用場景

  • 緩存系統:高併發讀、低頻寫入,ReadWriteLock 大幅提升吞吐。
  • 資源池管理:配合 Condition 實現有界隊列的生產消費模型。
  • 死鎖預防:使用 tryLock(timeout) 替代無限等待,超時後釋放已持有鎖並重試。

最佳實踐總結

  1. 優先使用 synchronized(JVM 優化後性能優異、代碼簡潔),僅在需要 Lock 進階特性時使用 ReentrantLock。
  2. 嚴格遵循 lock() -> try -> finally unlock() 模式。
  3. 讀多寫少場景選 ReentrantReadWriteLock,注意寫鎖降級規則。
  4. 公平鎖慎用,除非業務強制要求 FIFO。
  5. 善用 tryLock() 實現無鎖重試邏輯,避免死鎖。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved