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

Java 多線程編程:獲取線程返回值的兩種核心模式——輪詢與回調機制深度解析

     編輯:Java 程式設計入門

問題背景:線程執行的非確定性

在多線程編程中,主線程無法預知子線程何時執行完畢。直接調用 getter 方法往往拿到的是初始值,而非線程處理後的結果。這是由線程調度的隨機性決定的——即便提高線程優先級,也無法保證 100% 先執行完畢。

錯誤示範:直接獲取導致數據不一致

public class ReturnThreadInfo extends Thread {
    private String str = "Hello"; // 初始值
    
    public void run() {
        this.str = "Hello World!"; // 線程任務:修改值
    }
    
    public String getThreadInfo() {
        return this.str;
    }
}

public class Main {
    public static void main(String[] args) {
        ReturnThreadInfo thread = new ReturnThreadInfo();
        thread.start(); // 啟動線程
        System.out.println(thread.getThreadInfo()); // 輸出 "Hello" 而非預期的 "Hello World!"
    }
}

原因分析:主線程執行 `println` 時,子線程的 `run()` 方法大概率尚未執行,導致讀到舊值。

方案一:輪詢機制——主動等待結果就緒

核心思想

主線程循環調用獲取方法,直到返回值不再是初始標識值。

代碼實現

public class Main {
    public static void main(String[] args) {
        ReturnThreadInfo thread = new ReturnThreadInfo();
        thread.start();
        
        // 輪詢循環
        while (true) {
            String result = thread.getThreadInfo();
            if (!"Hello".equals(result)) { // 判斷是否為初始值
                System.out.println(result); // 輸出 "Hello World!"
                break;
            }
            // 建議加入短暫睡眠降低 CPU 佔用
            try { Thread.sleep(10); } catch (InterruptedException ignored) {}
        }
    }
}

優缺點分析

優點缺點
實現簡單,無需修改線程類忙等待消耗 CPU 資源
邏輯直觀,易於理解無法精確控制檢查頻率
線程數多時性能急劇下降

方案二:回調機制——反向通知,零等待開銷

核心思想

好萊塢原則:「別調用我們,我們會調用你。」線程執行完畢後,主動調用主線程提供的回調方法傳遞結果。

代碼實現

// 主類提供靜態回調方法
public class Main {
    public static void main(String[] args) {
        ReturnThreadInfo thread = new ReturnThreadInfo();
        thread.start(); // 啟動後主線程可繼續做其他事或結束
    }
    
    // 回調入口:線程結束時調用
    public static void receiveStr(String result) {
        System.out.println("收到線程結果: " + result);
    }
}

// 線程類在 run() 結束前回調
public class ReturnThreadInfo extends Thread {
    private String str = "Hello";
    
    public void run() {
        this.str = "Hello World!";
        Main.receiveStr(str); // 關鍵:主動通知主線程
    }
}

進階模式:基於接口的多監聽者回調

當有多個對象關心線程結果時,定義回調接口實現觀察者模式:


// 1. 定義回調接口
public interface ThreadResultListener {
    void onThreadComplete(String result);
}

// 2. 線程類維護監聽器列表
public class ReturnThreadInfo extends Thread {
    private List listeners = new ArrayList<>();
    private String result;
    
    public void addListener(ThreadResultListener listener) {
        listeners.add(listener);
    }
    
    public void run() {
        this.result = "Hello World!";
        // 通知所有監聽者
        for (ThreadResultListener listener : listeners) {
            listener.onThreadComplete(result);
        }
    }
}

// 3. 多個業務類實現接口
public class BusinessA implements ThreadResultListener {
    public void onThreadComplete(String result) {
        System.out.println("業務A處理: " + result);
    }
}

public class BusinessB implements ThreadResultListener {
    public void onThreadComplete(String result) {
        System.out.println("業務B處理: " + result);
    }
}

現代 Java 最佳實踐:Future/Callable 與 CompletableFuture

JDK 5+ 提供了更優雅的標準化方案:

// 使用 Callable + FutureTask (JDK 5)
Callable task = () -> {
    Thread.sleep(1000); // 模擬耗時操作
    return "Hello World!";
};

FutureTask futureTask = new FutureTask<>(task);
new Thread(futureTask).start();

String result = futureTask.get(); // 阻塞獲取結果,自動同步
System.out.println(result);

// 使用 CompletableFuture (JDK 8+,推薦)
CompletableFuture.supplyAsync(() -> {
    Thread.sleep(1000);
    return "Hello World!";
}).thenAccept(result -> System.out.println("異步結果: " + result));

總結對比

方案適用場景複雜度性能推薦指數
直接獲取教學演示/單元測試極低不可用⭐
輪詢簡單任務、無法修改線程類低差 (CPU 浪費)⭐⭐
回調/監聽器事件驅動架構、多消費者中優⭐⭐⭐⭐
Future/Callable需要阻塞等待結果的場景中優⭐⭐⭐⭐
CompletableFuture現代異步編程、組合操作中高優⭐⭐⭐⭐⭐

最佳實踐建議

  1. 優先選擇 CompletableFuture:JDK 8+ 環境首選,支持鏈式調用、異常處理、組合操作
  2. 回調模式適用於事件驅動架構:如 GUI 事件、網絡回調、消息隊列消費
  3. 避免輪詢:除非極簡單場景且無法引入額外依賴
  4. 線程安全:共享數據使用 `volatile`、原子類或鎖保護
  5. 異常傳遞:回調/Future 均需完善異常處理機制
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved