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) | 簡單業務 | 類級別單例資源 |
String、Integer 等常量池對象(不同類共享同一把鎖)this 公開可見對象(死鎖風險)不能。volatile 僅保證可見性與有序性,不保證原子性。tickets-- 為「讀-改-寫」三步操作,volatile 無法防止競態條件。需配合 AtomicInteger 或 synchronized。
Thread-0 賣出第 5 張 Thread-1 賣出第 4 張 Thread-2 賣出第 3 張 Thread-0 賣出第 2 張 Thread-1 賣出第 1 張