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

Java 執行緒同步機制:synchronized 關鍵字保護共享資料

     編輯:Java 程式設計入門

同步鎖解決共享資料競態條件

當多執行緒同時存取共享可變資料時,會發生競態條件導致資料不一致。Java 提供 synchronized 關鍵字實現內建鎖,確保同一時間僅有一條執行緒執行受保護的程式碼區塊。

完整程式碼:SyThreadDemo.java

public class SyThreadDemo {
    public static void main(String[] args) {
        trade ft = new trade(); // 共享資料物件
        addThread tt1 = new addThread(ft, "add");
        decThread tt2 = new decThread(ft, "dec");
        tt1.start();
        tt2.start();
    }
}

// 同步類別:封裝共享資料與同步操作
class trade {
    private String transName;
    private double amount;

    // synchronized 修飾實例方法 → 鎖定 this 物件
    synchronized void update(String transName, double amount) {
        this.transName = transName;
        this.amount = amount;
        System.out.println(this.transName + " " + this.amount);
    }
}

// 增加資金執行緒
class addThread extends Thread {
    private trade ft;
    addThread(trade ft, String name) { super(name); this.ft = ft; }

    public void run() {
        for (int i = 0; i < 10; i++)
            ft.update("add", 2000.0);
    }
}

// 減少資金執行緒
class decThread extends Thread {
    private trade fd;
    decThread(trade fd, String name) { super(name); this.fd = fd; }

    public void run() {
        for (int i = 0; i < 10; i++)
            fd.update("dec", -2000.0);
    }
}

執行結果示意(交替輸出,無資料錯亂)

add 2000.0
dec -2000.0
add 2000.0
dec -2000.0
...
add 2000.0
dec -2000.0

synchronized 三種鎖定範圍

用法鎖定物件適用場景
synchronized 修飾實例方法this(目前實例)保護該實例的非靜態欄位
synchronized 修飾靜態方法類別物件(ClassName.class)保護靜態欄位
synchronized(obj) { ... }obj(指定物件)細粒度鎖、跨實例協調

本範例鎖定分析

  • trade.update() 為實例同步方法 → 鎖定 trade 實例(ft/fd 指向同一物件)
  • 兩條執行緒呼叫同一物件的同步方法 → 互斥執行,transName 與 amount 成對更新
  • 若移除 synchronized,輸出會出現「add -2000.0」等錯亂組合

同步原理與記憶體可見性

  1. 互斥性:同一時間僅一執行緒持有鎖
  2. 可見性:解鎖前對共享變數的寫入,對後續獲得鎖的執行緒可見(隱含記憶體屏障)
  3. 重入性:同一執行緒可重複獲得同一鎖

常見錯誤與避坑指南

  • ❌ 鎖定不同物件:synchronized(new Object()) 每次建立新鎖,失去保護效果
  • ❌ 鎖定不可變物件:String、Integer 等可能被常數池共用,導致非預期互斥
  • ❌ 同步區塊過大:包含 I/O、睡眠等耗時操作,降低並發度
  • ✅ 縮小同步範圍:僅保護核心共享資料操作
  • ✅ 使用 final 鎖物件:private final Object lock = new Object();
  • ✅ 考慮 ReadWriteLock:讀多寫少場景提升並發

現代替代方案(Java 5+)

// 显式鎖:更靈活,支援可中斷、超時、公平鎖
private final ReentrantLock lock = new ReentrantLock();
public void update(...) {
    lock.lock();
    try { /* 關鍵區 */ } finally { lock.unlock(); }
}

// 原子類別:無鎖執行緒安全
private final AtomicReference name = new AtomicReference<>();
private final AtomicLong amount = new AtomicLong();

掌握 synchronized 是理解 Java 並發基石,進而駕馭 JUC 套件(Lock、Atomic*、ConcurrentHashMap 等)的前提。

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