class RunnableDemo implements Runnable {
private int tickets = 5;
@Override public void run() {
for (int i = 0; i < 10; i++) {
Thread.sleep(500);
if (tickets > 0) System.out.println("車票: " + tickets--);
}
}
}
// 三線程共享同一 RunnableDemo 實例
// 輸出示例:5 4 3 2 1 2 (出現負數/重複,數據競爭)
public void run() {
for (int i = 0; i < 10; i++) {
Thread.sleep(500);
synchronized (this) { // 鎖住當前實例
if (tickets > 0) System.out.println("車票: " + tickets--);
}
}
}
public synchronized void show() { // 隱式鎖 this
if (tickets > 0) System.out.println("車票: " + tickets--);
}
public void run() {
for (int i = 0; i < 10; i++) show();
}
車票: 5 車票: 4 車票: 3 車票: 2 車票: 1
| 維度 | 同步代碼塊 | 同步方法 |
|---|---|---|
| 鎖對象 | 顯式指定(this、類對象、任意對象) | 隱式:實例方法鎖 this,靜態方法鎖 Class 對象 |
| 粒度控制 | 精細,僅鎖關鍵區段 | 整個方法 |
| 靈活性 | 高,可針對不同共享資源用不同鎖 | 低,方法級粗粒度 |
| 性能 | 略優(鎖範圍小) | 略差 |
| 可讀性 | 稍低 | 高,語義清晰 |
不能。volatile 僅保證可見性與有序性,不保證原子性。tickets-- 是「讀-改-寫」三步操作,volatile 無法防止競爭。需配合 AtomicInteger 或 synchronized/Lock。
java.util.concurrent 包下的線程安全集合、原子類、鎖(ReentrantLock)。synchronized 時,盡量縮小同步塊範圍,避免在同步塊中調用耗時操作(IO、睡眠、外部服務)。synchronized (MyClass.class) 或 static synchronized 方法。String、基本類型包裝類作為鎖(常量池/自動裝箱導致鎖對象不一致)。