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

Java 多執行緒回傳值實戰:Callable 與 FutureTask 完整指南

     編輯:Java 相關知識

掌握 Java 非同步運算:Callable、FutureTask 與執行緒池整合應用

相較於 Runnable 無法回傳值且無法拋出受檢異常,Callable<V> 介面支援泛型回傳值與異常傳播。配合 FutureTask 與執行緒池,可實現真正的非同步運算與結果獲取。本文完整解析核心 API 與實戰模式。

核心類別關係圖

  • Callable<V>:函數式介面,單一方法 call() 回傳 V 型別結果
  • Future<V>:非同步計算結果控制代理,提供 get()、cancel()、isDone() 等方法
  • FutureTask<V>:實作 RunnableFuture,同時是 Runnable(可提交執行緒池)與 Future(可獲取結果)
  • ExecutorService:執行緒池管理,支援 submit() 提交 Callable/FutureTask

完整程式碼實作

package com.future.test;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * Callable 與 FutureTask 綜合示範
 */
public class CallableFutureDemo {
    
    public static void main(String[] args) {
        // 建立單一執行緒執行緒池
        ExecutorService executor = Executors.newSingleThreadExecutor();
        
        // 建立 FutureTask 包裝 Callable 任務
        FutureTask futureTask = new FutureTask<>(new Callable() {
            @Override
            public String call() throws Exception {
                // 模擬耗時運算(10 秒)
                System.out.println("【任務開始】執行耗時運算...");
                Thread.sleep(10_000);
                System.out.println("【任務完成】運算結束");
                return "運算結果:11111";
            }
        });
        
        // 提交任務至執行緒池(非阻塞)
        executor.execute(futureTask);
        System.out.println("【主執行緒】任務已提交,繼續處理其他業務...");
        
        // 主執行緒可繼續做其他工作
        doOtherWork();
        
        // 獲取結果(支援超時控制)
        String result = null;
        try {
            // 等待最多 5 秒,超時拋出 TimeoutException
            result = futureTask.get(5, TimeUnit.SECONDS);
            System.out.println("【結果獲取】成功:" + result);
        } catch (TimeoutException e) {
            System.err.println("【超時】任務執行超過 5 秒,取消任務");
            futureTask.cancel(true); // true 表示中斷正在執行的任務
        } catch (InterruptedException e) {
            System.err.println("【中斷】主執行緒被中斷");
            futureTask.cancel(true);
        } catch (ExecutionException e) {
            System.err.println("【異常】任務執行拋出異常:" + e.getCause().getMessage());
            futureTask.cancel(true);
        } finally {
            // 關閉執行緒池
            executor.shutdown();
            System.out.println("【執行緒池】已關閉");
        }
        
        System.out.println("最終結果:" + result);
    }
    
    private static void doOtherWork() {
        // 模擬主執行緒處理其他業務
        for (int i = 1; i <= 3; i++) {
            System.out.println("【主執行緒】處理其他業務 " + i);
            try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
        }
    }
}

關鍵執行流程說明

  1. 任務提交:executor.execute(futureTask) 非阻塞提交,主執行緒立即繼續
  2. 並行處理:主執行緒執行 doOtherWork(),工作執行緒執行 call()
  3. 結果獲取:futureTask.get(5, TimeUnit.SECONDS) 阻塞等待,支援超時
  4. 異常處理:三種異常分別對應超時、中斷、任務內部錯誤
  5. 資源清理:finally 區塊確保執行緒池關閉

進階應用模式

1. 批次提交多個 Callable 任務

List> tasks = new ArrayList<>();
for (int i = 0; i < 10; i++) {
    final int taskId = i;
    FutureTask task = new FutureTask<>(() -> {
        Thread.sleep(1000);
        return taskId * 2;
    });
    tasks.add(task);
    executor.execute(task);
}

// 收集所有結果
for (FutureTask task : tasks) {
    try {
        System.out.println("任務結果:" + task.get());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

2. 使用 invokeAll 批次等待

List> callables = Arrays.asList(
    () -> { Thread.sleep(1000); return "任務A"; },
    () -> { Thread.sleep(2000); return "任務B"; }
);

List> futures = executor.invokeAll(callables);
for (Future f : futures) {
    System.out.println(f.get());
}

常見陷阱與最佳實踐

問題解決方案
get() 無限阻塞永遠使用帶超時的 get(timeout, unit)
異常吞沒ExecutionException 需呼叫 getCause() 取得真實異常
執行緒池洩漏必須在 finally 區塊呼叫 shutdown() 或 shutdownNow()
取消任務無效cancel(true) 需任務內部定期檢查 Thread.interrupted()

Java 8+ CompletableFuture 現代替代方案

Java 8 引入 CompletableFuture 提供更豐富的非同步組合 API(thenApply、thenCompose、allOf 等),新專案建議優先使用:

CompletableFuture.supplyAsync(() -> {
    Thread.sleep(1000);
    return "非同步結果";
}).thenAccept(result -> System.out.println(result));
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved