多線程是 Java 核心競爭力之一。本文系統整理建立線程三種方式、Thread/Runnable/Callable 差異、線程生命週期狀態轉換、start() vs run() 關鍵區別,配合可執行範例程式碼。
class MyThread extends Thread {
private int tickets;
public MyThread(int tickets) { this.tickets = tickets; }
@Override
public void run() {
for (; tickets > 0; tickets--) {
System.out.println("當前線程:" + getName() + " 賣出第 " + tickets + " 張票");
if (tickets == 1) System.out.println("票賣完,線程:" + getName());
}
}
}
// 使用
new MyThread(100).start();
new MyThread(100).start(); // 兩個線程各自賣 100 張 (不同任務)
getName() / this
class MyTask implements Runnable {
private int tickets;
public MyTask(int tickets) { this.tickets = tickets; }
@Override
public void run() {
for (; tickets > 0; tickets--) {
System.out.println("當前線程:" + Thread.currentThread() + " 賣出第 " + tickets + " 張票");
}
}
}
// 使用
MyTask task = new MyTask(100); // 單一任務實例
new Thread(task, "線程A").start();
new Thread(task, "線程B").start(); // 兩線程共享同一任務 (賣同 100 張票)
Thread.currentThread()@FunctionalInterface 支援 Lambda:new Thread(() -> {...}).start()
class MyCallable implements Callable {
private int tickets;
public MyCallable(int tickets) { this.tickets = tickets; }
@Override
public String call() {
for (; tickets > 0; tickets--) {
System.out.println("當前線程:" + Thread.currentThread() + " 賣出第 " + tickets + " 張票");
}
return tickets == 0 ? "所有票賣完" : "票未賣完";
}
}
// 使用
Callable callable = new MyCallable(100);
FutureTask future = new FutureTask<>(callable); // 實作 Runnable + Future
new Thread(future, "線程A").start();
new Thread(future, "線程B").start();
try {
String result = future.get(); // 阻塞等待結果
System.out.println("任務結果:" + result);
} catch (Exception e) { e.printStackTrace(); }
call() 有返回值、可拋受檢異常FutureTask 同時實作 Runnable、Futurefuture.get() 阻塞取得結果,get(timeout, unit) 可設超時Callable c = () -> "result"; | 維度 | Thread | Runnable | Callable |
|---|---|---|---|
| 繼承其他類 | 不可 (單繼承) | 可 | 可 |
| 取得當前線程 | this / getName() | Thread.currentThread() | Thread.currentThread() |
| 共享任務 | 不可 | 可 | 可 |
| 返回值 | 無 | 無 | 有 (泛型) |
| 拋異常 | 無 | 無 | 可拋受檢異常 |
| 直接作 Target | 是 (本身是 Thread) | 是 | 否 (需 FutureTask 包裝) |

new Thread(),僅是普通物件start() 後,等待 CPU 調度sleep()、wait()suspend() (不建議,易死鎖)wait() 釋放鎖進入等待集stop() (不建議,不安全)isAlive():新建/終止 回傳 false,其他 true| 項目 | start() | run() |
|---|---|---|
| 作用 | 啟動新線程,由 JVM 呼叫 run() | 普通方法呼叫,當前線程執行 |
| 線程狀態 | 新建 → 就緒 → 執行 | 狀態不變 (仍為新建) |
| 可重複呼叫 | 否 (拋 IllegalThreadStateException) | 可 (普通方法) |
| 呼叫後能否 start | 否 (狀態已變) | 否 (run() 執行後狀態非新建) |
永遠不要直接呼叫 run()!必須用 start() 啟動線程。
Thread 簡單、Runnable 靈活共享、Callable 有返回值start() 啟動線程,run() 只是方法 —— 這是面試必考、實戰必錯的核心區別