三線程輪流打印 A、B、C 共 10 次。初始嘗試用共享 Integer gData = 0 配合 synchronized(gData) 協調,結果僅打印 A。
Integer 為不可變類,內部 final int value。每次 gData++ 實際是:
gData = Integer.valueOf(gData.intValue() + 1); // 新建 Integer 物件
線程 A 更新後持有新物件引用,線程 B/C 仍持有舊物件(值仍為 0),導致條件 gData % 3 == n 永不滿足。
驗證:在迴圈中打印 gData 可見 B/C 線程讀到的值未變。
AtomicInteger gData = new AtomicInteger(0);
// 線程中
synchronized (gData) {
if (gData.get() % 3 == n) {
System.out.print(info + " ");
gData.incrementAndGet(); // 原子更新
i++;
}
}
AtomicInteger 內部用 CAS 保證原子性,物件引用不變,所有線程見到同一物件的最新值。
Object A = new Object(), B = new Object(), C = new Object();
new MyThread(C, A, "A").start(); // prev=C, curr=A
new MyThread(A, B, "B").start();
new MyThread(B, C, "C").start();
class MyThread extends Thread {
private final Object prev, curr;
private final String info;
public MyThread(Object prev, Object curr, String info) { ... }
public void run() {
for (int i = 10; i > 0; i--) {
synchronized (prev) {
synchronized (curr) {
System.out.print(info + " ");
curr.notify(); // 喚醒下一個
}
prev.wait(); // 等待上一個喚醒
}
}
}
}
三把鎖環狀傳遞,嚴格保證執行順序。需注意啟動順序與微小 sleep 確保進入 wait 狀態。
Atomic*、ConcurrentHashMap)或同步器(CountDownLatch、Semaphore)wait/notify 雖基礎,但能精準控制線程協作順序