| 維度 | 繼承 Thread | 實作 Runnable |
| 類別層次 | 強制單繼承,侵入性強 | 可實作多介面,靈活 |
| 啟動方式 | new MyThread().start() | new Thread(new MyRunnable()).start() |
| 共享資料 | 需額外傳遞引用 | 天然共享同一 Runnable 實例 |
| 推薦度 | 簡單測試 | 生產環境首選 |
二、程式碼對比
1. 繼承 Thread
class TimePrinter extends Thread {
int pause; String name;
TimePrinter(int p, String n) { pause=p; name=n; }
public void run() {
while(true) {
System.out.println(name + ": " + new Date());
Thread.sleep(pause);
}
}
}
new TimePrinter(1000, "Fast").start();
new TimePrinter(3000, "Slow").start();
2. 實作 Runnable (推薦)
class TimePrinter implements Runnable {
int pause; String name;
TimePrinter(int p, String n) { pause=p; name=n; }
public void run() { /* 同前 */ }
}
new Thread(new TimePrinter(1000, "Fast")).start();
new Thread(new TimePrinter(3000, "Slow")).start();
三、synchronized 關鍵字
每個物件擁有一把內部鎖 (Monitor),synchronized 方法/區塊需先獲得鎖才能執行。
銀行帳戶案例 — 未同步 (錯誤)
class Account {
float balance;
void deposit(float amt) { balance += amt; }
void withdraw(float amt) { balance -= amt; }
}
併發存/提導致 balance 更新丟失 (Race Condition)。
修正 — 同步關鍵操作
class Account {
float balance;
public synchronized void deposit(float amt) { balance += amt; }
public synchronized void withdraw(float amt) { balance -= amt; }
public float getBalance() { return balance; } // 唯讀可不同步
}
deposit、withdraw 互斥,同一時間僅一線程執行。
getBalance 不加鎖,讀取不阻塞寫入,寫入不阻塞讀取 (但可能讀到舊值,視業務接受度)。
四、進階同步技巧
synchronized(this) 同步實例方法;synchronized(Account.class) 同步靜態方法。
- 縮小同步區塊:
synchronized(lock) { critical section },減少鎖持有時間。
- 避免在同步區塊呼叫外部方法/阻塞 I/O,防止死鎖與效能退化。
五、Java 5+ 替代方案
java.util.concurrent.locks.ReentrantLock 提供可中斷鎖、公平鎖、條件變數 (Condition) 等進階功能,複雜場景優先考慮。
- 上一篇文章: Java 多線程精要:線程優先級限制與調度策略
- 下一篇文章: Java 多線程進階:線程組、線程通信、yield 讓步、守護線程
Copyright ©
程式碼之家 All Rights Reserved