首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 多執行緒入門指南(7):向執行緒傳遞資料的三種核心模式

     編輯:Java 相關知識

背景:同步 vs 非同步資料流

傳統同步呼叫: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 封裝。

缺點

  • 參數過多時建構子膨脹,需用 Builder 模式或參數物件重構。

模式二:Setter/欄位注入(靈活、適合 Runnable)

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();
    }
}

優點

  • 支援預設值、可選參數、分步設定。
  • 符合 JavaBean 慣例,易於框架整合(Spring 注入等)。

缺點與風險

  • 必須確保「設定完成 → 能見度」:若 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();
    }
}

核心概念

  • 回呼 = 事件通知:執行緒主動呼叫外部提供的介面方法,類似 Windows API 回呼、JavaScript 事件監聽器。
  • 實現控制反轉 (IoC):執行緒不依賴具體處理邏輯,只依賴介面。
  • 可雙向傳遞:Data 物件可攜帶輸入參數與輸出結果。

三種模式對比選型指南

維度建構子注入Setter/欄位注入回呼介面
資料時機建構時(啟動前)建構後、啟動前執行期間(動態)
資料方向單向:主→執行緒單向:主→執行緒雙向:執行緒↔外部
安全性最高(final + happens-before)需注意能見度介面契約保證
適用場景固定初始化參數可選參數、框架整合流式處理、事件通知、協作式運算
範例連線參數、檔案路徑策略物件、監聽器SaxParser、SwingWorker、訂閱發佈

進階補充:更現代的替代方案

  • ExecutorService + Callable/Future:有回傳值的任務,Future.get() 阻塞取得結果。
  • CompletableFuture:非阻塞鏈式組合、異步回呼、多任務編排。
  • BlockingQueue / ConcurrentLinkedQueue:生產者-消費者模式,執行緒間安全傳遞資料流。
  • ThreadLocal:執行緒私有資料儲存,避免參數層層傳遞。

一句話總結:啟動前固定參數用建構子,啟動前可選參數用 Setter(注意 volatile),運行中動態互動用回呼介面;現代專案優先考慮 CompletableFuture 與 BlockingQueue。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved