在類別內部需要執行支線任務(如背景計算、資料同步、通知發送)時,若不想為此創建獨立類別或實作 Runnable 介面,可使用匿名內部類直接在方法內定義並啟動 Thread。本文解析此模式的語法結構、執行流程、變數捕獲規則與現代替代方案。
package com.zj.concurrency;
public class StartFromMethod {
private Thread thread;
private final int number;
private int count = 1;
public StartFromMethod(int number) {
this.number = number;
}
public void runTask() {
if (thread == null) {
thread = new Thread() { // 匿名內部類繼承 Thread
@Override
public void run() {
while (true) {
System.out.println("Thread-" + number + " run " + count + " time(s)");
if (++count == 3) return;
}
}
};
thread.start(); // 啟動執行緒
}
}
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
new StartFromMethod(i).runTask();
}
}
}
Thread-0 run 1 time(s)
Thread-0 run 2 time(s)
Thread-1 run 1 time(s)
Thread-1 run 2 time(s)
Thread-2 run 1 time(s)
Thread-2 run 2 time(s)
Thread-3 run 1 time(s)
Thread-3 run 2 time(s)
Thread-4 run 1 time(s)
Thread-4 run 2 time(s)
5 個執行緒交錯執行,每個執行緒印出 2 次後結束。輸出順序不固定,取決於作業系統排程器。
new Thread() { // 建立 Thread 子類別的匿名實例
@Override
public void run() { // 覆寫 run() 方法
// 任務邏輯
}
};
等價於:定義一個繼承 Thread 的區域類別,並立即實例化。適用於「一次性使用、邏輯簡單、不需複用」的場景。
number)count)無限制,透過隱含的 this$0 參考外部實例final;Java 8+:僅需「事實上不可變」即可| 方式 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| 繼承 Thread (匿名內部類) | 語法簡潔、可直接用 this 存取 Thread 方法 | 單一繼承限制、任務與執行緒耦合 | 極簡、一次性、無需複用的背景任務 |
| 實作 Runnable (匿名/Lambda) | 關注點分離、可提交給執行緒池、支援多種執行方式 | 需額外 new Thread(runnable) | 所有生產級非同步任務、需資源控制的場景 |
// Java 8+ Lambda 取代匿名內部類
public void runTaskModern() {
if (thread == null) {
thread = new Thread(() -> {
while (true) {
System.out.println("Thread-" + number + " run " + count + " time(s)");
if (++count == 3) return;
}
});
thread.start();
}
}
private final ExecutorService executor = Executors.newFixedThreadPool(10);
public void runTaskPooled() {
executor.submit(() -> {
while (true) {
System.out.println("Thread-" + number + " run " + count + " time(s)");
if (++count == 3) return;
}
});
}
// 應用關閉時優雅關閉
public void shutdown() {
executor.shutdown();
try {
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
}
優點:執行緒複用、資源可控、支援 Future/CompletionStage、避免無限制創建執行緒導致 OOM。
run() 中未捕獲的異常會導致執行緒靜默終止,建議在 run 內部包裝 try-catch 並記錄日誌count 為實例欄位,多執行緒存取需加 synchronized、AtomicInteger 或 ThreadLocal 保護static 巢狀類別或 WeakReferencethread.setDaemon(true)匿名內部類啟動執行緒是 Java 早期實現「方法內非同步」的經典模式,語法直觀、即寫即用。現代開發中,建議優先採用 Lambda + ExecutorService 組合:語法更簡潔、資源可控、符合生產環境非同步處理最佳實踐。理解匿名內部類的變數捕獲與生命週期特性,有助於維護舊代碼並避免常見併發陷阱。