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

Java 多線程同步核心:synchronized 同步塊 vs 同步方法、鎖對象選擇、JVM 鎖優化演進

     編輯:Java 綜合教學

問題場景:賣票系統並發超賣

class TicketSeller implements Runnable {
    private int tickets = 5;
    public void run() {
        for (int i = 0; i < 10; i++) {
            if (tickets > 0) {
                try { Thread.sleep(500); } catch (InterruptedException e) {}
                System.out.println(Thread.currentThread().getName() + " 賣出第 " + tickets-- + " 張");
            }
        }
    }
}
// 三線程並發輸出:5,4,3,2,1,2,1,0,-1...  出現負數與重複

方案一:同步代碼塊

public void run() {
    for (int i = 0; i < 10; i++) {
        synchronized (this) { // 鎖當前實例
            if (tickets > 0) {
                System.out.println(Thread.currentThread().getName() + " 賣出第 " + tickets-- + " 張");
            }
        }
    }
}

方案二:同步方法

public synchronized void sell() { // 鎖 this
    if (tickets > 0) {
        System.out.println(Thread.currentThread().getName() + " 賣出第 " + tickets-- + " 張");
    }
}
public void run() {
    for (int i = 0; i < 10; i++) {
        sell();
        try { Thread.sleep(500); } catch (InterruptedException e) {}
    }
}

核心區別與鎖對象選擇

維度同步代碼塊同步實例方法同步靜態方法
鎖對象括號內任意對象當前實例Class 對象
粒度可精確到幾行代碼整個方法整個方法
靈活性高(可用不同鎖分離資源)低低
典型用法synchronized(lockObj)簡單業務類級別單例資源

鎖對象最佳實踐

  • 私有 final Object lock = new Object(); — 封裝性最好,防止外部誤用
  • 避免鎖 String、Integer 等常量池對象(不同類共享同一把鎖)
  • 避免鎖 this 公開可見對象(死鎖風險)

JVM 鎖優化演進(JDK 6+)

  1. 偏向鎖:無競爭時,執行緒 ID 寫入 Mark Word,後續進出零開銷
  2. 輕量級鎖:輕度競爭,CAS 更新 Mark Word 指向棧中 Lock Record,自旋等待
  3. 重量級鎖:激烈競爭,OS Mutex 陷入內核,線程阻塞/喚醒
  4. 鎖消除:JIT 逃逸分析發現鎖對象無逃逸 → 直接移除同步
  5. 鎖粗化:連續對同一對象加鎖/解鎖 → 合併為一次大範圍同步

volatile 能替代嗎?

不能。volatile 僅保證可見性與有序性,不保證原子性。tickets-- 為「讀-改-寫」三步操作,volatile 無法防止競態條件。需配合 AtomicInteger 或 synchronized。

正確輸出驗證

Thread-0 賣出第 5 張
Thread-1 賣出第 4 張
Thread-2 賣出第 3 張
Thread-0 賣出第 2 張
Thread-1 賣出第 1 張
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved