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

Java 異步回調實戰:Future 模式、CompletableFuture 與自定義回調接口

     編輯:Java 相關知識

同步調用阻塞線程,異步回調釋放線程做別的事。本文展示三種異步回調實現層次:經典 Future 模式(手工實現)、JDK 8 CompletableFuture(標準庫)、自定義回調接口(輕量級),附完整可運行代碼與場景選型建議。

一、核心角色模型

角色說明對應代碼
調用者發起請求、持有憑證、稍後獲取結果Main / Controller
憑證異步操作的句柄,提供獲取結果/取消/查狀態方法Future / CompletableFuture / CallbackToken
真實數據耗時運算產出的最終結果RealData / 返回值
執行者在背景線程執行耗時任務Thread / ExecutorService

二、方案一:手工 Future 模式(教學級)

// 1. 數據接口
interface Data { String getContent(); }

// 2. 真實數據:構造耗時
class RealData implements Data {
    private final String content;
    public RealData(int count, char c) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < count; i++) {
            sb.append(c);
            try { Thread.sleep(100); } catch (InterruptedException ignored) {}
        }
        content = sb.toString();
    }
    public String getContent() { return content; }
}

// 3. 未來數據:憑證,同步等待真實數據就緒
class FutureData implements Data {
    private RealData realData;
    private boolean ready = false;

    public synchronized void setRealData(RealData rd) {
        if (ready) return; // 防重複設置
        this.realData = rd;
        ready = true;
        notifyAll(); // 喚醒等待線程
    }

    public synchronized String getContent() {
        while (!ready) {
            try { wait(); } catch (InterruptedException ignored) {}
        }
        return realData.getContent();
    }
}

// 4. 服務端:接收請求 → 返回憑證 → 後台構建真實數據
class Host {
    public Data request(final int count, final char c) {
        final FutureData future = new FutureData();
        new Thread(() -> {
            RealData real = new RealData(count, c);
            future.setRealData(real);
        }).start();
        return future; // 立即返回憑證
    }
}

// 5. 客戶端使用
public class FutureDemo {
    public static void main(String[] args) {
        Host host = new Host();
        Data d1 = host.request(10, 'A');
        Data d2 = host.request(20, 'B');
        Data d3 = host.request(30, 'C');

        System.out.println("主線程繼續做其他事...");
        try { Thread.sleep(500); } catch (InterruptedException ignored) {}

        System.out.println("d1: " + d1.getContent()); // 阻塞直到就緒
        System.out.println("d2: " + d2.getContent());
        System.out.println("d3: " + d3.getContent());
    }
}

三、方案二:JDK 8 CompletableFuture(生產標準)

ExecutorService executor = Executors.newFixedThreadPool(4);

public CompletableFuture supplyAsync(int count, char c) {
    return CompletableFuture.supplyAsync(() -> {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < count; i++) {
            sb.append(c);
            try { Thread.sleep(100); } catch (InterruptedException ignored) {}
        }
        return sb.toString();
    }, executor);
}

// 使用:鏈式組合、異常處理、多任務編排
public void demo() {
    CompletableFuture f1 = supplyAsync(10, 'A');
    CompletableFuture f2 = supplyAsync(20, 'B');
    CompletableFuture f3 = supplyAsync(30, 'C');

    // 並行等待所有完成,彙總結果
    CompletableFuture.allOf(f1, f2, f3).thenRun(() -> {
        try {
            System.out.println("全部完成: " + f1.get() + ", " + f2.get() + ", " + f3.get());
        } catch (Exception e) { throw new RuntimeException(e); }
    });

    // 或:任一完成即處理
    CompletableFuture.anyOf(f1, f2, f3).thenAccept(res -> 
        System.out.println("最快完成: " + res));
}

四、方案三:自定義回調接口(輕量、無依賴)

// 1. 回調接口
interface Callback {
    void onSuccess(T result);
    void onFailure(Throwable cause);
}

// 2. 請求載體
class Request {
    private final Callback callback;
    private final Supplier task;

    public Request(Supplier task, Callback callback) {
        this.task = task;
        this.callback = callback;
    }

    public void start() {
        new Thread(() -> {
            try {
                T result = task.get();
                callback.onSuccess(result);
            } catch (Throwable t) {
                callback.onFailure(t);
            }
        }).start();
    }
}

// 3. 使用
new Request<>(() -> {
    Thread.sleep(2000);
    return "異步結果";
}, new Callback() {
    public void onSuccess(String r) { System.out.println("成功: " + r); }
    public void onFailure(Throwable t) { t.printStackTrace(); }
}).start();

System.out.println("主線程繼續...");

五、三大方案對比選型

維度手工 FutureCompletableFuture自定義回調
API 豐富度低極高(組合、異常、超時、線程池)低
依賴無JDK 8+無
線程池管理手工內建/自定義手工
回調地獄風險中低(鏈式)高(嵌套)
適用場景教學、極簡項目、JDK 7 以下**生產首選**、微服務、複雜編排輕量級、Android 早期、嵌入式

六、進階避坑指南

  • 線程池必須有界:new ThreadPoolExecutor(core, max, ..., new ArrayBlockingQueue<>(cap)),防止任務堆積 OOM。
  • 回調執行線程:CompletableFuture 默認在完成任務的線程執行回調,UI 更新需切換到 EDT/FX 線程。
  • 異常傳播:exceptionally()、handle() 統一處理,避免異常丟失。
  • 取消支持:future.cancel(true) 配合任務內部 Thread.interrupted() 檢查實現響應式取消。
  • 內存洩漏:長生命週期 Future 持有大對象引用,及時 future = null 或用弱引用。

異步回調是高併發、響應式系統的基石。建議:新項目直接上 CompletableFuture,舊項目逐步遷移;僅在極度受限環境下考慮手工 Future 或自定義回調。

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