當多個執行緒同時存取共享資源(變數、檔案、資料庫連線)時,若缺乏協調,會導致資料不一致或競爭條件。同步機制確保「同一時間只有一個執行緒能進入關鍵區段」,保證操作的原子性與可見性。
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)。i++ 不是原子操作(讀取、加一、寫入三步驟)。long/double 64 位元讀寫在 32 位元 JVM 可能非原子,需加 volatile 或用 AtomicLong。volatile 保證可見性與禁止指令重排,但不保證複合操作原子性。// 執行緒 1 // 執行緒 2
synchronized(A) { synchronized(B) {
synchronized(B) { synchronized(A) {
// 死結 // 死結
} }
}
預防策略:
tryLock(timeout)(需 java.util.concurrent.locks.Lock)。同步是多執行緒安全的基石。掌握 synchronized 區塊/方法、volatile、原子類別與死鎖預防,能寫出正確且高效的並發程式。