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

Java 線程同步進階(四):同步方法、同步塊與 Lock 接口實戰

     編輯:Java 相關知識

承接前文,通過計分板組件 ScoreLabel 實戰演示多線程環境下的同步策略演進。

競態條件實戰:計分邏輯

public class ScoreLabel extends JLabel implements CharacterListener {
    private volatile int score = 0;
    private int char2type = -1;
    private CharacterSource generator, typist;

    public synchronized void newCharacter(CharacterEvent ce) {
        if (ce.source == generator) {           // 產生字符
            if (char2type != -1) { score--; setScore(); }
            char2type = ce.character;
        } else {                                // 用戶輸入
            if (char2type != ce.character) score--;
            else { score++; char2type = -1; }
            setScore();
        }
    }
    // resetGenerator/resetTypist/resetScore/setScore 均同步
}

痛點:newCharacter() 由多線程並發調用,涉及多變量(score、char2type)的複合操作,volatile 單變量可見性無法解決「檢查-執行」原子性問題。

同步方法 vs 同步塊

物件鎖機制

  • 同步方法隱式鎖定 this(實例鎖)
  • 靜態同步方法鎖定 Class 對象(類鎖)
  • 實例鎖與類鎖獨立,可同時持有

同步與非同步方法共存風險

非同步方法繞過鎖檢查,可任意時間執行 → 防衛性設計:所有訪問共享狀態的方法均應同步。

縮小鎖範圍:同步塊

public void newCharacter(CharacterEvent ce) {
    if (ce.source == generator) {
        synchronized (this) { /* 生產者邏輯 */ }
    } else {
        synchronized (this) { /* 消費者邏輯 */ }
    }
}

或鎖定共享數據對象而非 this,進一步降低爭用。

JDK 5 Lock 接口:顯式鎖控制

private Lock scoreLock = new ReentrantLock();

public void newCharacter(CharacterEvent ce) {
    if (ce.source == generator) {
        scoreLock.lock();
        try { /* 生產者邏輯 */ } finally { scoreLock.unlock(); }
    } else {
        scoreLock.lock();
        try { /* 消費者邏輯 */ } finally { scoreLock.unlock(); }
    }
}

Lock 核心優勢

  • 靈活作用域:鎖獲取/釋放不綁定方法邊界
  • 可傳遞/存儲:多物件共享同一 Lock,單物件持有多把鎖
  • 非阻塞嘗試:tryLock() / tryLock(timeout) 避免無限等待
  • 公平鎖選項:new ReentrantLock(true) 保證 FIFO 獲取,防飢餓

重構優化:策略方法提煉

private synchronized void newGeneratorCharacter(int c) { /* ... */ }
private synchronized void newTypistCharacter(int c) { /* ... */ }

public synchronized void newCharacter(CharacterEvent ce) {
    if (ce.source == generator) newGeneratorCharacter(ce.character);
    else newTypistCharacter(ce.character);
}

注意:私有策略方法仍加 synchronized,防止未來維護者誤調用(嵌套鎖機制保證同一線程重入不阻塞)。

可重入鎖與死鎖防範

  • 嵌套鎖計數:同一線程重複獲取同一鎖計數遞增,退出遞減至 0 釋放
  • ReentrantLock 支援 getHoldCount()、isHeldByCurrentThread()、getQueueLength() 監控
  • 死鎖難檢測:系統無法自動解決,需通過鎖排序、超時機制、避免回調中持有鎖等工程規範預防

選型建議

場景推薦方案
簡單同步、方法級粒度synchronized 方法
需縮小鎖範圍、高併發熱點synchronized 塊
跨方法鎖範圍、需 tryLock/公平性/多條件Lock 接口
靜態+非靜態方法混合同步Lock 更直觀(不綁定 this/Class)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved