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

Java 併發鎖機制:ReentrantLock 與 ReadWriteLock 完整實戰

     編輯:Java 相關知識

JDK 5 java.util.concurrent.locks 提供比 synchronized 更強大的鎖 API:**可中斷、可超時、公平/非公平、條件變數、讀寫分離**。本文實戰示範 ReentrantLock 獨佔鎖與 ReentrantReadWriteLock 讀寫鎖的核心用法。

ReentrantLock:獨佔可重入鎖


class LockCounter {
    private final Lock lock = new ReentrantLock(); // 預設非公平
    private long value = 0;
    private int ops = 0;

    public void add(long v) {
        lock.lock(); // 必須在 try 之前
        try {
            Thread.sleep(1000); // 模擬耗時操作
            value += v;
            ops++;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock(); // 必須在 finally 釋放
        }
    }
    public long getValue() { return value; }
    public int getOps() { return ops; }
}

關鍵模式:lock/unlock 必配 try/finally


lock.lock();
try {
    // 臨界區
} finally {
    lock.unlock();
}

ReentrantReadWriteLock:讀寫分離鎖

「讀讀共存、讀寫互斥、寫寫互斥」。適合**讀多寫少**場景 (快取、配置、註冊表)。


class RWCache {
    private final ReadWriteLock rwl = new ReentrantReadWriteLock();
    private final Lock r = rwl.readLock();
    private final Lock w = rwl.writeLock();
    private Map<String, String> data = new HashMap<>();

    public String get(String key) {
        r.lock();
        try { return data.get(key); }
        finally { r.unlock(); }
    }
    public void put(String key, String val) {
        w.lock();
        try { data.put(key, val); }
        finally { w.unlock(); }
    }
    // 升級鎖 (Read → Write) 不支援,會死鎖,需釋放讀鎖再取寫鎖
}

完整驗證程式:模擬併發讀寫


import java.util.concurrent.*;

public class LockDemo {
    static class RWTest {
        final ReadWriteLock lock = new ReentrantReadWriteLock();
        final Lock r = lock.readLock(), w = lock.writeLock();
        int value = 0, writes = 0;

        void write(int v) {
            w.lock();
            try {
                System.out.printf("Write %d start%n", v);
                Thread.sleep(500);
                value += v; writes++;
                System.out.printf("Write %d done%n", v);
            } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
            finally { w.unlock(); }
        }
        String read() {
            r.lock();
            try {
                System.out.println("Read start");
                Thread.sleep(300);
                return value + ":" + writes;
            } catch (InterruptedException e) { Thread.currentThread().interrupt(); return "err"; }
            finally { r.unlock(); }
        }
    }

    public static void main(String[] args) throws Exception {
        RWTest test = new RWTest();
        ExecutorService es = Executors.newCachedThreadPool();

        // 提交 2 寫 + 2 讀 + 1 寫
        es.submit(() -> test.write(10));
        es.submit(() -> test.write(20));
        es.submit(() -> System.out.println("Read1: " + test.read()));
        es.submit(() -> System.out.println("Read2: " + test.read()));
        Future<String> last = es.submit(() -> { test.write(30); return "ok"; });

        last.get(); // 等待最後寫入完成
        es.shutdownNow();
        System.out.println("Final: " + test.read());
    }
}

執行流程說明


Write 10 start
Write 10 done          ← 寫鎖獨佔,第二個寫等待
Write 20 start
Write 20 done
Read start             ← 讀鎖共享,兩個讀同時進行
Read start
Read1: 30:2
Read2: 30:2
Write 30 start         ← 讀寫互斥,寫等待讀完成
Write 30 done
Final: 60:3

進階特性對比表

特性synchronizedReentrantLockReentrantReadWriteLock
可中斷獲取❌lockInterruptibly() ✅✅
超時獲取❌tryLock(timeout) ✅✅
公平鎖❌ (JVM 內部)new ReentrantLock(true) ✅new ReentrantReadWriteLock(true) ✅
條件變數wait/notifynewCondition() 多條件 ✅✅
讀寫分離❌❌✅
效能 (低爭用)極佳 (JVM 優化)略低略低

選型建議

  • 簡單同步、低爭用 → synchronized (JVM 偏向鎖、輕量鎖、消除鎖優化)。
  • 需中斷/超時/公平/多條件 → ReentrantLock。
  • 明顯讀多寫少 (快取、配置、註冊表) → ReentrantReadWriteLock。
  • 高併發計數器 → LongAdder / AtomicLong (無鎖 CAS)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved