實現 Runnable 接口是 Java 創建線程的標準方式之一,它將「任務邏輯」與「線程控制」解耦,支援線程池提交、Lambda 表達式、函數式編程,是現代並發編程的推薦範式。本文通過完整代碼示例,講解實現步驟、構造方法選擇、命名規範、常見誤區。
Runnable,重寫 run() 方法編寫任務邏輯。Thread 實例,將任務對象傳入構造器。thread.start() 啟動線程(不是 run())。package com.example.thread;
public class RunnableDemo {
static class MyTask implements Runnable {
private final String taskName;
public MyTask(String taskName) {
this.taskName = taskName;
}
@Override
public void run() {
// 任務邏輯
for (int i = 1; i <= 3; i++) {
System.out.printf("[%s] %s - Step %d%n",
Thread.currentThread().getName(), taskName, i);
try { Thread.sleep(200); } catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 重置中斷標誌
return; // 優雅退出
}
}
}
}
public static void main(String[] args) {
// 1. 創建任務實例(可復用)
MyTask task1 = new MyTask("訂單處理");
MyTask task2 = new MyTask("庫存扣減");
// 2. 創建線程並指定名稱(生產環境強烈建議)
Thread t1 = new Thread(task1, "Order-Thread-1");
Thread t2 = new Thread(task2, "Stock-Thread-1");
// 3. 啟動線程
t1.start();
t2.start();
// 4. 主線程等待子線程結束(演示用,實際用線程池)
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("主線程結束");
}
}
// 僅傳任務,線程名自動分配 "Thread-N"
new Thread(runnable)
// 傳任務 + 顯式線程名(推薦)
new Thread(runnable, "Business-Name-1")
// 傳線程組 + 任務 + 名稱(罕用)
new Thread(threadGroup, runnable, "Name")
線程名規範:業務模塊-功能-序號,如 Order-PayCallback-3,便於 jstack/Arthas/日誌排查。
Runnable sharedTask = () -> System.out.println("Shared: " + Thread.currentThread().getName());
new Thread(sharedTask, "T1").start();
new Thread(sharedTask, "T2").start();
new Thread(sharedTask, "T3").start();
三線程共享同一 Runnable 實例,若任務內有非線程安全狀態(如計數器),必須自行同步(synchronized/AtomicInteger)。
// 匿名內部類等價
new Thread(() -> {
System.out.println("Lambda 任務運行中...");
// 多行邏輯
}, "Lambda-Thread").start();
// 錯誤!在主線程同步執行,不會創建新線程
new Thread(task).run();
// 正確
new Thread(task).start();
| 維度 | Runnable | extends Thread |
|---|---|---|
| 繼承限制 | 無,可繼承其他類 | 單繼承,無法復用邏輯 |
| 任務復用 | 同一實例可提交多線程/線程池 | 每線程需 new 子類實例 |
| 線程池兼容 | 原生支援 executor.submit(runnable) | 需包裝或改寫 |
| Lambda 支援 | 函數式接口,完美適配 | 不支援 |
| 訪問線程屬性 | 需 Thread.currentThread() | 直接 this.getName() |
// 定義線程池(實際應配置化、監控化)
ExecutorService pool = new ThreadPoolExecutor(
4, 8, 60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100),
new ThreadFactoryBuilder().setNameFormat("Biz-Worker-%d").build(),
new ThreadPoolExecutor.AbortPolicy()
);
// 提交 Runnable 任務
pool.submit(() -> {
// 業務邏輯
return result; // 若需返回值用 Callable
});
// 關閉
pool.shutdown();
手動 new Thread 缺點:無限制創建導致 OOM、無隊列緩衝、無拒絕策略、無監控指標、線程名不可控。
Runnable 將任務與線程分離,是並發編程的基石。new Thread 僅用於簡單測試或特殊場景(如需要繼承 Thread 重寫 interrupt())。