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

Java 多執行緒同步實戰:從 synchronized 失敗案例到正確鎖共享模式

     編輯:Java 相關知識

核心概念:同步靠「共享同一把鎖」

synchronized 背後是物件監視器。**多執行緒必須競爭同一個物件實例的鎖**,才能實現互斥。若每個執行緒鎖住自己的 this,根本無法同步。

錯誤示範:鎖住各自的 this

class MyThread implements Runnable {
    private int id;
    public MyThread(int id) { this.id = id; }
    @Override
    public synchronized void run() { // 鎖住 this (每個實例不同)
        for (int i = 0; i < 100; i++)
            System.out.println("Thread " + id + " : " + i);
    }
}
public class Demo {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++)
            new Thread(new MyThread(i)).start(); // 10 把不同的鎖,完全無同步效果
    }
}

結果:10 執行緒輸出交錯亂序。

正確模式一:外部共享鎖物件傳入

class MyThread implements Runnable {
    private int id;
    private final Object lock; // 共享鎖
    public MyThread(int id, Object lock) { this.id = id; this.lock = lock; }
    @Override
    public void run() {
        synchronized (lock) { // 競爭同一把鎖
            for (int i = 0; i < 100; i++)
                System.out.println("Thread " + id + " : " + i);
        }
    }
}
public class Demo {
    public static void main(String[] args) {
        Object sharedLock = new Object(); // 唯一共享鎖
        for (int i = 0; i < 10; i++)
            new Thread(new MyThread(i, sharedLock)).start();
    }
}

結果:執行緒 0 印完 0~99,執行緒 1 再印 0~99,依序進行。

正確模式二:static 成員鎖(類別級共享)

class MyThread implements Runnable {
    private int id;
    private static final Object LOCK = new Object(); // 類別級唯一鎖
    public MyThread(int id) { this.id = id; }
    @Override
    public void run() {
        synchronized (LOCK) { ... }
    }
}

無需建構子傳遞,所有實例天然共享 MyThread.LOCK。

正確模式三:static synchronized 方法(鎖住 Class 物件)

class MyThread implements Runnable {
    private int id;
    public MyThread(int id) { this.id = id; }
    @Override
    public void run() {
        taskHandler(id); // 呼叫靜態同步方法
    }
    private static synchronized void taskHandler(int id) { // 鎖住 MyThread.class
        for (int i = 0; i < 100; i++)
            System.out.println("Thread " + id + " : " + i);
    }
}

static synchronized 等同 synchronized (MyThread.class),同樣達到全域互斥。

關鍵差異對照

寫法鎖物件共享範圍適用場景
synchronized void instanceMethod()this同一實例實例級資料保護
synchronized (sharedObj)外部傳入/靜態欄位所有持有相同引用的執行緒跨實例協作、精細鎖粒度
static synchronized void staticMethod()Xxx.class所有實例、類別級靜態資料、單例模式、類別級資源

避坑提醒

  • 字串常數池陷阱: synchronized("lock") 看似共享,實則可能因常數池優化導致不同類別載入器載入的相同字串不是同一物件,極度危險。
  • 鎖物件不可變: synchronized (Integer.valueOf(1)) 同理,自動拆箱/裝箱可能產生新物件。
  • 盡量用 final Object lock = new Object(); 明確語意,防止誤覆寫引用。
  • 私有鎖原則: 鎖物件最好 private,避免外部代碼刻意/誤用同一把鎖造成活鎖或死鎖。

進階:ReentrantLock 替代方案

private static final Lock LOCK = new ReentrantLock();
public void run() {
    LOCK.lock();
    try { ... } finally { LOCK.unlock(); }
}

提供可中斷、逾時、公平鎖等進階控制,同樣需靜態共享實例。

總結

同步的本質是**多執行緒圍繞同一個物件鎖排隊**。寫法千變萬化,核心只有一條:**確保參與同步的所有執行緒,看到的是同一個鎖物件實例**。

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