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

Java 多執行緒同步機制詳解:synchronized、死鎖與最佳實務

     編輯:Java 相關知識

什麼是執行緒同步?

當多個執行緒同時存取共享資源(變數、檔案、資料庫連線)時,若缺乏協調,會導致資料不一致或競爭條件。同步機制確保「同一時間只有一個執行緒能進入關鍵區段」,保證操作的原子性與可見性。

經典案例:火車票超賣問題

class SaleTickets implements Runnable {
    private int ticket = 1; // 只有一張票

    public void run() {
        if (ticket > 0) {           // 檢查
            Thread.sleep(...);      // 模擬網路延遲
            ticket--;               // 扣款
            System.out.println("售出");
        } else {
            System.out.println("售完");
        }
    }
}

兩個執行緒同時通過 if (ticket > 0) 檢查,導致同一張票被賣兩次,甚至 ticket 變成負數。

解決方案一:同步程式碼區塊

public void run() {
    synchronized (this) { // 鎖住目前物件
        if (ticket > 0) {
            Thread.sleep(...);
            ticket--;
            System.out.println(Thread.currentThread().getName() + " 售出,剩餘:" + ticket);
        } else {
            System.out.println("抱歉,已售完");
        }
    }
}
  • synchronized(obj) 取得 obj 的內建鎖(monitor)。
  • 鎖住 this 會鎖定整個物件;也可用私有 final Object lock = new Object(); 縮小鎖粒度。

解決方案二:同步方法

public synchronized void sale() {
    // 關鍵邏輯
}
  • 非靜態同步方法鎖住 this;靜態同步方法鎖住 Class 物件。
  • 優點:程式碼簡潔。缺點:鎖粒度較粗,且無法被繼承(子類別覆寫時需自行加 synchronized)。

進階主題

原子操作與 volatile

  • i++ 不是原子操作(讀取、加一、寫入三步驟)。
  • long/double 64 位元讀寫在 32 位元 JVM 可能非原子,需加 volatile 或用 AtomicLong。
  • volatile 保證可見性與禁止指令重排,但不保證複合操作原子性。

死鎖

// 執行緒 1                    // 執行緒 2
synchronized(A) {               synchronized(B) {
    synchronized(B) {               synchronized(A) {
        // 死結                     // 死結
    }                           }
}

預防策略:

  1. 固定鎖獲取順序(避免循環等待)。
  2. 減少巢狀同步區塊。
  3. 使用 tryLock(timeout)(需 java.util.concurrent.locks.Lock)。

效能考量

  • 同步有開銷(鎖獲取/釋放、記憶體屏障)。
  • 優先使用不可變物件、區域變數、ThreadLocal 避免共享。
  • 必要時才同步,並縮小關鍵區塊範圍。

總結

同步是多執行緒安全的基石。掌握 synchronized 區塊/方法、volatile、原子類別與死鎖預防,能寫出正確且高效的並發程式。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved