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

Java 線程同步實戰(八):synchronized 關鍵字與售票系統線程安全

     編輯:Java 相關知識

通過經典「多窗口售票」案例,直觀演示線程不安全現象與 synchronized 兩種用法的修復效果。

問題現場:線程不安全

class TicketSource implements Runnable {
    private int ticket = 10;
    public void run() {
        for (int i=1; i<50; i++) {
            if (ticket > 0) {
                Thread.sleep(1000); // 放大併發窗口
                System.out.println(Thread.currentThread().getName() 
                    + "號窗口賣出" + this.ticket-- + "號票");
            }
        }
    }
}
// 三線程並發:new Thread(mt,"1").start()...

輸出錯誤:出現重複票號、負數票號、總賣出超過 10 張。

線程不安全輸出示例

方案一:同步方法

public synchronized void sale() {
    if (ticket > 0) {
        System.out.println(Thread.currentThread().getName() 
            + "號窗口賣出" + this.ticket-- + "號票");
    }
}
public void run() {
    for (int i=1; i<50; i++) {
        try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
        sale(); // 委託同步方法
    }
}

方案二:同步塊

public void run() {
    for (int i=1; i<50; i++) {
        synchronized (this) { // 鎖定當前實例
            if (ticket > 0) {
                try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
                System.out.println(Thread.currentThread().getName() 
                    + "號窗口賣出" + this.ticket-- + "號票");
            }
        }
    }
}

輸出對比

兩種方案均輸出正確:1-10 號票各賣出一次,無重無漏。

同步後正確輸出

關鍵注意點

  • 鎖對象一致性:多線程必須共享同一把鎖(本例同一 TicketSource 實例)
  • 鎖粒度:同步塊可縮小範圍,但本例邏輯簡單,方法級同步足矣
  • 位置關鍵:synchronized 必須覆蓋「檢查條件 + 修改狀態」完整原子操作,錯位會導致保護失效
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved