Java 讓多線程如此簡單高效,以至有人說它簡直是天生的。雖然比其他語言容易得多,仍有程式員對線程感到困惑。main() 也是一個線程,可做有用工作。只有需要多線程時才需創建新線程。
Thread 是具體類(非抽象),封裝線程行為。創建線程需衍生新類,覆寫 run() 完成工作。不直接調用 run(),而是調用 start(),由它調用 run()。
import java.util.*;
class TimePrinter extends Thread {
int pauseTime;
String name;
public TimePrinter(int x, String n) {
pauseTime = x; name = n;
}
public void run() {
while (true) {
try {
System.out.println(name + ":" + new Date(System.currentTimeMillis()));
Thread.sleep(pauseTime);
} catch (Exception e) { System.out.println(e); }
}
}
static public void main(String args[]) {
TimePrinter tp1 = new TimePrinter(1000, "Fast Guy");
tp1.start();
TimePrinter tp2 = new TimePrinter(3000, "Slow Guy");
tp2.start();
}
}
本例創建兩個新線程(含 main() 共三個),按 1 秒和 3 秒間隔顯示時間。但若類已有父類,無法繼承 Thread(Java 單繼承)。同時有人避免繼承 Thread 以免強加類層次。此時用 Runnable 介面。
Runnable 僅有一個 run() 方法,實現類須實現它。運行語義略異:不能直接創建實現類物件並運行,必須從 Thread 實例內部運行。
import java.util.*;
class TimePrinter implements Runnable {
int pauseTime;
String name;
public TimePrinter(int x, String n) { pauseTime = x; name = n; }
public void run() {
while (true) {
try {
System.out.println(name + ":" + new Date(System.currentTimeMillis()));
Thread.sleep(pauseTime);
} catch (Exception e) { System.out.println(e); }
}
}
static public void main(String args[]) {
Thread t1 = new Thread(new TimePrinter(1000, "Fast Guy"));
t1.start();
Thread t2 = new Thread(new TimePrinter(3000, "Slow Guy"));
t2.start();
}
}
許多程式員偏好 Runnable,因繼承 Thread 強加類層次,且 Runnable 更符合「組合優於繼承」原則,靈活性更高。
| 維度 | 繼承 Thread | 實現 Runnable |
|---|---|---|
| 類層次 | 強加繼承關係 | 無侵入,可繼承其他類 |
| 線程邏輯復用 | 難(單繼承限制) | 易(同一 Runnable 可給多 Thread) |
| 訪問 this | 直接訪問線程方法 | 需通過 Thread.currentThread() |
| 推薦場景 | 簡單獨立線程任務 | 大多數場景,尤其需共享邏輯時 |
現代 Java 開發中,Runnable 配合線程池(ExecutorService)是主流實踐,避免頻繁創建銷毀線程開銷。