將主程式類實作 Runnable 介面,而非繼承 Thread,實現「主類即任務」的合併模式。Runnable 僅定義 run() 方法,**不具備執行緒控制能力**,必須顯式建立 Thread 實例並傳入 this 才能啟動。
public class Counter3 extends Applet implements Runnable {
private int count = 0;
private boolean runFlag = true;
private Thread selfThread = null; // 執行緒引用
public void init() {
// UI 初始化...
}
public void run() { // 實作 Runnable
while (true) {
try { selfThread.sleep(100); } catch (InterruptedException ignored) {}
if (runFlag) t.setText(String.valueOf(count++));
}
}
class StartL implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (selfThread == null) {
selfThread = new Thread(Counter3.this); // 包裝 Runnable
selfThread.start(); // 啟動執行緒
}
}
}
}
StartL 檢查 selfThread == null。new Thread(Counter3.this):將實作 Runnable 的主類實例傳入。start() → JVM 初始化執行緒 → 回呼 run()。runFlag 控制計數暫停/繼續。| 優點 | 缺點 |
|---|---|
| 程式碼集中,訪問成員變數無需跨物件引用 | 單一主類實例只能對應**一個**執行緒(若需多執行緒需建立多個主類實例或改用獨立 Runnable 類) |
| 避免額外類別定義,簡化小型程式結構 | 職責混雜:UI、執行緒控制、業務邏輯耦合在一起,違反單一職責原則 |
| 適合簡單動畫、單一背景任務場景 | 難以獨立測試 run() 邏輯 |
implements Runnable 就能多執行緒。Runnable 只是任務定義,**必須**配合 new Thread(runnable).start() 才能並行執行。Thread.sleep() 是實例方法。sleep() 是 **static** 方法,作用於**當前執行緒**。範例中 selfThread.sleep(100) 雖能編譯運行,但語意易誤解,建議改為 Thread.sleep(100)。// 使用 Lambda + ExecutorService,職責分離更清晰
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
while (!Thread.currentThread().isInterrupted()) {
if (runFlag) SwingUtilities.invokeLater(() -> t.setText(String.valueOf(count++)));
try { Thread.sleep(100); } catch (InterruptedException e) { break; }
}
});
Runnable + 主類合併模式是早期 Java 教學常見寫法,理解其「任務與執行緒分離」的本質至關重要。實務開發中,**優先採用獨立 Runnable/Callable 配合執行緒池**,保持架構清晰、可測、可擴展。