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

Java 多線程編程:Lock 接口與 ReentrantLock 實戰詳解

     編輯:Java 相關知識

Lock 接口核心優勢

相較於 synchronized,Lock 提供更豐富的控制能力:

  • 可中斷獲取鎖:lockInterruptibly() 響應中斷,避免死鎖無限等待。
  • 嘗試非阻塞獲取:tryLock() 立即返回,tryLock(timeout, unit) 支持超時。
  • 公平鎖選項:構造函數指定公平性,公平鎖保證請求順序,吞吐量較低。
  • 多條件變量:newCondition() 可創建多個 Condition,實現精細化通知(如生產者/消費者不同隊列)。
  • 顯式鎖定/釋放:代碼可讀性更強,支持非塊結構鎖定(跨方法加解鎖)。

標準使用模式

Lock lock = new ReentrantLock(); // 或 new ReentrantLock(true) 公平鎖

lock.lock();
try {
    // 临界區操作
} finally {
    lock.unlock(); // 必須在 finally 中釋放
}

完整示例:替換 synchronized 實現線程安全輸出

public class LockDemo {
    public static void main(String[] args) {
        Outputer outputer = new Outputer();

        new Thread(() -> {
            while (true) {
                try { Thread.sleep(10); } catch (InterruptedException ignored) {}
                outputer.output("zhangsan");
            }
        }, "Thread-A").start();

        new Thread(() -> {
            while (true) {
                try { Thread.sleep(10); } catch (InterruptedException ignored) {}
                outputer.output("lisi");
            }
        }, "Thread-B").start();
    }
}

class Outputer {
    private final Lock lock = new ReentrantLock();

    public void output(String name) {
        lock.lock();
        try {
            for (char c : name.toCharArray()) {
                System.out.print(c);
            }
            System.out.println();
        } finally {
            lock.unlock();
        }
    }
}

進階特性演示

可中斷鎖獲取

public void interruptibleLock(Lock lock) {
    try {
        lock.lockInterruptibly(); // 可被 interrupt() 中斷
        try {
            // do work
        } finally {
            lock.unlock();
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt(); // 保留中斷狀態
        // 處理中斷邏輯
    }
}

超時嘗試獲取鎖

public boolean tryLockWithTimeout(Lock lock, long timeout, TimeUnit unit) {
    try {
        return lock.tryLock(timeout, unit); // 超時返回 false,不阻塞無限期
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        return false;
    }
}

多條件變量:生產者-消費者

class BoundedBuffer {
    private final Lock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();
    private final Queue queue = new LinkedList<>();
    private final int capacity;

    public void put(T item) throws InterruptedException {
        lock.lock();
        try {
            while (queue.size() == capacity) notFull.await();
            queue.add(item);
            notEmpty.signal();
        } finally { lock.unlock(); }
    }

    public T take() throws InterruptedException {
        lock.lock();
        try {
            while (queue.isEmpty()) notEmpty.await();
            T item = queue.poll();
            notFull.signal();
            return item;
        } finally { lock.unlock(); }
    }
}

ReentrantLock 實現原理速覽

基於 AQS(AbstractQueuedSynchronizer),使用 state 表示鎖重入次數,exclusiveOwnerThread 記錄持有線程。非公平鎖嘗試 CAS 直接搶佔,公平鎖檢查 AQS 隊列是否有前驅節點。Condition 依賴 AQS 內部等待隊列實現。

最佳實踐建議

  • 優先使用 try-with-resources 模式(Java 17+ Lock 實現 AutoCloseable)或 finally 確保釋放。
  • 避免在鎖內調用未知代碼(如回調),防止死鎖或性能抖動。
  • 高併發讀多寫少場景優先考慮 ReadWriteLock 或 StampedLock。
  • 公平鎖僅在嚴格需要請求順序時使用,吞吐量通常下降 2-3 倍。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved