| 維度 | 繼承 Thread 類 | 實現 Runnable 接口 |
|---|---|---|
| 代碼存放位置 | 子類 run() 方法 | 實現類 run() 方法 |
| 繼承限制 | 佔用單繼承名額 | 無繼承限制,可繼承其他類 |
| 線程邏輯復用 | 困難,邏輯綁定在線程類 | 易復用,同一 Runnable 可交給多個 Thread |
| 異常處理 | run() 可拋棄查異常 | run() 不可拋棄查異常,需內部 try-catch |
| 推薦場景 | 簡單測試、無邏輯復用需求 | 企業級開發、線程池、任務解耦 |
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " : " + i);
}
}
}
public class Demo {
public static void main(String[] args) {
new MyThread().start(); // 線程名:Thread-0
new MyThread().start(); // 線程名:Thread-1
}
}
缺點:每個線程對象 = 一個任務邏輯,無法共享任務實例;若需共享數據需額外傳遞參數。
class TicketSeller implements Runnable {
private int tickets = 100;
private final Object lock = new Object(); // 共享鎖
@Override
public void run() {
while (true) {
synchronized (lock) { // 必須用同一把鎖
if (tickets > 0) {
try { Thread.sleep(10); } catch (InterruptedException ignored) {}
System.out.println(Thread.currentThread().getName() + " 賣出第 " + tickets-- + " 張票");
} else {
break;
}
}
}
}
}
public class Demo {
public static void main(String[] args) {
TicketSeller task = new TicketSeller(); // 單一任務實例,數據共享
new Thread(task, "窗口-A").start();
new Thread(task, "窗口-B").start();
new Thread(task, "窗口-C").start();
new Thread(task, "窗口-D").start();
}
}
優勢:任務與線程分離,同一任務實例可被多線程並發執行,天然支持共享數據(如賣票案例的 tickets)。
多線程訪問共享資源時,必須保證三要素:
Object 或 this / Class 對象synchronized(lock) { 临界区 }synchronized(this) 與 synchronized(lock) 的區別:前者鎖住當前實例,後者可自定義鎖對象,粒度更可控。
生產環境極少直接 new Thread(),推薦使用線程池:
ExecutorService pool = Executors.newFixedThreadPool(4);
Runnable task = () -> System.out.println(Thread.currentThread().getName() + " 執行任務");
for (int i = 0; i < 10; i++) pool.submit(task);
pool.shutdown();
優勢:線程復用、任務隊列、拒絕策略、可監控、避免 OOM。
Runnable + 線程池:解耦任務邏輯,支持共享數據,適配現代並發框架。Thread 繼承:僅用於極簡場景或教學演示。