傳統同步呼叫:result = method(param),參數與回傳值在同一呼叫堆疊自然流動。
多執行緒非同步:thread.start() 立即返回,run() 在未來某時執行,**無法用參數/回傳值直接傳遞資料**。必須採用共享記憶體或訊息傳遞模式。
public class MyThread1 extends Thread {
private final String name; // final 確保不可變、安全發布
public MyThread1(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println("Hello " + name);
}
public static void main(String[] args) {
new MyThread1("World").start();
}
}
final 欄位配合 JMM 保證安全發布,無需額外同步。List、Map、自訂 DTO 封裝。public class MyThread2 implements Runnable {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println("Hello " + name);
}
public static void main(String[] args) {
MyThread2 task = new MyThread2();
task.setName("World"); // 建構後、start 前設定
new Thread(task).start();
}
}
start() 前未 volatile/synchronized/final 保護,run() 可能看見舊值(預設 null)。volatile,或在 start() 前完成所有設定並利用 Thread.start() 的 happens-before 語義(JLS 17.4.4:start() 之前的寫入,對執行緒內可見)。適用於:執行緒運行中需根據動態產生的資料向外部通知、或需從外部拉取資料。
// 資料載體
class Data { public int value = 0; }
// 處理介面(回呼契約)
interface Processor {
void process(Data data, int... numbers);
}
// 實作:累加
class SumProcessor implements Processor {
public void process(Data data, int... numbers) {
for (int n : numbers) data.value += n;
}
}
// 執行緒主動回呼
public class MyThread3 extends Thread {
private final Processor processor;
public MyThread3(Processor processor) {
this.processor = processor;
}
@Override
public void run() {
Data data = new Data();
int n1 = new Random().nextInt(1000);
int n2 = new Random().nextInt(2000);
int n3 = new Random().nextInt(3000);
processor.process(data, n1, n2, n3); // 回呼:將資料推送給外部
System.out.println(n1 + "+" + n2 + "+" + n3 + "=" + data.value);
}
public static void main(String[] args) {
new MyThread3(new SumProcessor()).start();
}
}
Data 物件可攜帶輸入參數與輸出結果。| 維度 | 建構子注入 | Setter/欄位注入 | 回呼介面 |
|---|---|---|---|
| 資料時機 | 建構時(啟動前) | 建構後、啟動前 | 執行期間(動態) |
| 資料方向 | 單向:主→執行緒 | 單向:主→執行緒 | 雙向:執行緒↔外部 |
| 安全性 | 最高(final + happens-before) | 需注意能見度 | 介面契約保證 |
| 適用場景 | 固定初始化參數 | 可選參數、框架整合 | 流式處理、事件通知、協作式運算 |
| 範例 | 連線參數、檔案路徑 | 策略物件、監聽器 | SaxParser、SwingWorker、訂閱發佈 |
Future.get() 阻塞取得結果。一句話總結:啟動前固定參數用建構子,啟動前可選參數用 Setter(注意 volatile),運行中動態互動用回呼介面;現代專案優先考慮 CompletableFuture 與 BlockingQueue。