最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中的異步操作CompletableFuture示例詳解

 更新時間:2026年02月11日 09:50:58   作者:曄子yy  
CompletableFuture是Java8引入的異步編程工具,支持非阻塞的鏈式調用和組合操作,提供了強大的異步任務編排能力,本文通過實例代碼講解Java中的異步操作CompletableFuture,感興趣的朋友跟隨小編一起看看吧

一、CompletableFuture概述

CompletableFuture? 是 Java 8 引入的一個功能強大的異步編程工具,它實現(xiàn)了FutureCompletionStage接口,提供了更靈活、更強大的異步任務編排能力。相比傳統(tǒng)的Future,它支持非阻塞的鏈式調用和組合操作。

二、CompletableFuture的核心特性

異步任務的創(chuàng)建與執(zhí)行

異步任務是CompletableFuture的基礎單元。關鍵在于區(qū)分任務的發(fā)起結果的獲取是兩個獨立的時機,這正是異步的本質。

//最簡單的異步調用,默認使用 ForkJoinPool.commonPool()
CompletableFuture<Integer> computeFuture = CompletableFuture.supplyAsync(() -> {
    Thread.sleep(1000);  // 模擬耗時計算
    return 42;
});

CompletableFuture底層是使用線程池幫我們去完成異步的一個調用,所以,我們也可以自定義線程池來實現(xiàn)異步操作。

//自定義線程池
ExecutorService bizExecutor = Executors.newFixedThreadPool(5, r -> {
    Thread t = new Thread(r);
    t.setName("BizExecutor-" + t.getId());
    return t;
});

實際開發(fā)中,強烈建議始終指定自定義線程池,避免業(yè)務代碼占用公共線程池影響系統(tǒng)穩(wěn)定性。

任務結果的鏈式處理

這是CompletableFuture最優(yōu)雅的特性,它將回調地獄轉換為流暢的管道。其中有三個重要的方法

  • thenApply:接受輸入,產(chǎn)生輸出,實際用作轉換函數(shù)
  • thenAccept:接受輸入,無輸出,作為數(shù)據(jù)的消費者
  • thenRun:無輸入,無輸出,可用作通知等操作
// 電商訂單處理流水線示例
CompletableFuture<Order> orderFuture = CompletableFuture
    // 階段1:創(chuàng)建訂單(有返回值)
    .supplyAsync(() -> orderService.createOrder(request), orderExecutor)
    // 階段2:驗證庫存(轉換結果)
    .thenApplyAsync(order -> {
        inventoryService.checkStock(order.getItems());
        return order.markAsValidated();
    }, inventoryExecutor)
    // 階段3:扣減庫存(消費結果,無返回)
    .thenAcceptAsync(order -> {
        inventoryService.deductStock(order.getItems());
        logger.info("庫存扣減完成,訂單號:{}", order.getId());
    }, inventoryExecutor)
    // 階段4:發(fā)送通知(純副作用操作)
    .thenRunAsync(() -> {
        notificationService.sendOrderCreated();
    }, notificationExecutor);

帶有Async后綴的方法(如thenApplyAsync)會在新線程中執(zhí)行,而不帶后綴的會在前一個任務完成的線程中執(zhí)行。在IO密集型場景使用Async版本可提高并發(fā)度。

多個任務組合

現(xiàn)實業(yè)務中很少有單一異步任務,更多是多個任務的協(xié)同。CompletableFuture提供了豐富的組合模式。

  • thenCombine:等待兩個都完成,然后合并
  • thenCompose: 前一個完成后再開始下一個
  • allOf: 等待所有(3+個)任務完成
// 場景:用戶詳情頁需要聚合多個服務的數(shù)據(jù)
public CompletableFuture<UserProfile> getUserProfile(String userId) {
    // 并行調用三個獨立服務
    CompletableFuture<UserInfo> userInfoFuture = 
        userService.getUserInfoAsync(userId);
    CompletableFuture<List<Order>> ordersFuture = 
        orderService.getUserOrdersAsync(userId);
    CompletableFuture<List<Address>> addressesFuture = 
        addressService.getUserAddressesAsync(userId);
    // thenCombine等待兩個都完成,然后合并
    CompletableFuture<UserWithOrders> userWithOrders = userInfoFuture
        .thenCombine(ordersFuture, (user, orders) -> {
            return new UserWithOrders(user, orders);
        });
    // thenCompose前一個完成后再開始下一個
    CompletableFuture<String> personalizedGreeting = userInfoFuture
        .thenCompose(user -> 
            greetingService.getGreetingAsync(user.getLanguage(), user.getName())
        );
    // allOf 等待所有(3+個)任務完成
    return CompletableFuture.allOf(
            userWithOrders, 
            addressesFuture, 
            personalizedGreeting
        )
        .thenApply(v -> {
            // 所有都完成后的聚合
            return new UserProfile(
                userWithOrders.join().getUser(),
                userWithOrders.join().getOrders(),
                addressesFuture.join(),
                personalizedGreeting.join()
            );
        });
}

這里有個要注意的點:allOf本身返回的是 CompletableFuture<Void>,不包含各子任務的結果。需要像上面示例中通過 join()或 get()來獲取,但注意這不會導致死鎖,因為此時所有子任務已確定完成。

異常處理

異步中的異常處理比同步更復雜,因為異常和業(yè)務代碼在時間、空間上都是解耦的。CompletableFuture 的異常處理是功能型、非侵入式的。

// 健壯的數(shù)據(jù)處理管道
CompletableFuture<Report> reportFuture = CompletableFuture
    .supplyAsync(() -> dataFetcher.fetchData(), dataExecutor)
    // exceptionally異常時提供降級值
    .exceptionally(ex -> {
        log.warn("數(shù)據(jù)獲取失敗,使用緩存", ex);
        return cacheService.getCachedData();
    })
    // 對數(shù)據(jù)做處理,同時捕獲處理中的異常
    .thenApplyAsync(data -> {
        try {
            return dataProcessor.process(data);
        } catch (ProcessingException e) {
            throw new CompletionException("處理失敗", e);
        }
    }, processExecutor)
    // handle統(tǒng)一處理成功和失敗
    .handle((processedData, ex) -> {
        if (ex != null) {
            // 失敗路徑
            metrics.recordFailure(ex);
            return Report.errorReport("系統(tǒng)繁忙,請稍后重試");
        } else {
            // 成功路徑
            return Report.successReport(processedData);
        }
    })
    // whenComplete無論成功失敗都執(zhí)行(類似finally)
    .whenComplete((report, ex) -> {
        // 資源清理、日志記錄等
        cleanResources();
        log.info("報告生成完成,狀態(tài):{}", 
            ex == null ? "成功" : "失敗");
    });

exceptionally和handle 的區(qū)別

  • exceptionally:只在異常時觸發(fā),必須返回一個恢復值
  • handle:無論成功失敗都觸發(fā),通過第二個參數(shù)判斷狀態(tài)

建議在異步鏈的末尾使用 handle或 whenComplete做統(tǒng)一的最終處理,而不是在每個階段都捕獲異常。

三、性能優(yōu)化與注意事項

避免阻塞主線程

在Web請求線程中調用get()會阻塞整個請求

錯誤寫法:

public Result handleRequest() {
    CompletableFuture<Data> future = fetchDataAsync();
    return future.get();  // 阻塞,浪費容器線程
}

接下來展示正確寫法:

//完全異步
public CompletableFuture<Result> handleRequestAsync() {
    return fetchDataAsync()
        .thenApply(data -> convertToResult(data))
        .exceptionally(ex -> Result.error("處理失敗"));
}

合理使用線程池資源

線程池隔離原則:不同業(yè)務、不同重要級別的任務使用不同的線程池,避免相互影響。

根據(jù)任務類型的不同配置不同的線程池參數(shù)

public class ThreadPoolConfig {
    // CPU密集型:核心數(shù)+1
    @Bean("cpuIntensivePool")
    public ExecutorService cpuIntensivePool() {
        int coreSize = Runtime.getRuntime().availableProcessors() + 1;
        return new ThreadPoolExecutor(
            coreSize, coreSize * 2, 60L, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(1000),
            new NamedThreadFactory("cpu-pool")
        );
    }
    // IO密集型:可設置較大線程數(shù)
    @Bean("ioIntensivePool")  
    public ExecutorService ioIntensivePool() {
        return new ThreadPoolExecutor(
            20, 100, 60L, TimeUnit.SECONDS,
            new SynchronousQueue<>(),  // 無界隊列,快速響應
            new NamedThreadFactory("io-pool")
        );
    }
    // 定時/超時任務:使用ScheduledExecutor
    @Bean("timeoutPool")
    public ScheduledExecutorService timeoutPool() {
        return Executors.newScheduledThreadPool(5, 
            new NamedThreadFactory("timeout-pool"));
    }
}

四、總結

CompletableFuture 不僅僅是API的增強,更是編程范式的轉變。

核心價值:

  • 聲明式異步:從"如何做"到"做什么"的轉變
  • 組合式抽象:將并發(fā)復雜性封裝在簡潔的API之后
  • 函數(shù)式融合:將函數(shù)式編程與并發(fā)編程結合

正確使用CompletableFuture,可以構建出既高性能又易于維護的異步系統(tǒng)。

到此這篇關于Java中的異步操作CompletableFuture示例詳解的文章就介紹到這了,更多相關java異步CompletableFuture內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 通過一個命令輕松切換Java的版本

    通過一個命令輕松切換Java的版本

    這篇文章主要給大家介紹了如何通過一個命令輕松實現(xiàn)切換Java的版本,通過本文介紹的方法,大家就可以將jdk版本之間輕松切換,需要的朋友可以參考學習,下面跟著小編一起來看看吧。
    2017-05-05
  • Java?Servlet實現(xiàn)表白墻的代碼實例

    Java?Servlet實現(xiàn)表白墻的代碼實例

    最近用Servlet做了個小項目,分享給大家,下面這篇文章主要給大家介紹了關于Java?Servlet實現(xiàn)表白墻的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2023-02-02
  • Spring AOP與代理類的執(zhí)行順序級別淺析

    Spring AOP與代理類的執(zhí)行順序級別淺析

    這篇文章主要介紹了Spring AOP與代理類的執(zhí)行順序級別,關于 Spring AOP和Aspectj的關系,兩個都實現(xiàn)了切面編程,Spring AOP更多地是為了Spring框架本身服務的,而Aspectj具有更強大、更完善的切面功能
    2023-03-03
  • Springboot?No?bean?named?'XXXXX'?available?問題解決方法

    Springboot?No?bean?named?'XXXXX'?available?問

    這篇文章主要介紹了Springboot?No?bean?named?'XXXXX'?available?問題解決方法,解決方法也很簡單,盡量規(guī)范類的命名,注解中指定bean名稱,本文給大家介紹的非常詳細,需要的朋友可以參考下
    2023-07-07
  • Java字符串替換的三種方法實際應用

    Java字符串替換的三種方法實際應用

    這篇文章主要給大家介紹了關于Java字符串替換的三種方法,replace和replaceAll是JAVA中常用的替換字符的方法,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2023-11-11
  • 關于Idea清除緩存并重啟解決的問題

    關于Idea清除緩存并重啟解決的問題

    這篇文章主要介紹了關于Idea清除緩存并重啟解決的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-09-09
  • SpringBoot全局異常處理機制和配置攔截器方式

    SpringBoot全局異常處理機制和配置攔截器方式

    這篇文章主要介紹了SpringBoot全局異常處理機制和配置攔截器方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • SpringBoot實現(xiàn)過濾器Filter的三種方式

    SpringBoot實現(xiàn)過濾器Filter的三種方式

    過濾器Filter由Servlet提供,基于函數(shù)回調實現(xiàn)鏈式對網(wǎng)絡請求與響應的攔截與修改,本文講給大家詳細介紹SpringBoot實現(xiàn)過濾器Filter的三種方式,需要的朋友可以參考下
    2023-08-08
  • Spring空值和特殊字符的注入方式

    Spring空值和特殊字符的注入方式

    文章介紹了如何通過創(chuàng)建類、配置文件和測試代碼來實現(xiàn)空值和特殊字符注入,具體包括定義屬性、生成set方法、配置對象創(chuàng)建和屬性注入、以及編寫測試代碼進行驗證
    2024-11-11
  • 詳解Java中的數(shù)組與字符串相關知識

    詳解Java中的數(shù)組與字符串相關知識

    這篇文章主要介紹了詳解Java中的數(shù)組與字符串相關知識,包括操作字符串的一些基本方法列舉,需要的朋友可以參考下
    2015-09-09

最新評論

藁城市| 巴中市| 武清区| 赤水市| 海门市| 社旗县| 和林格尔县| 上虞市| 天水市| 梅河口市| 西藏| 五台县| 明水县| 泰兴市| 宝清县| 清远市| 易门县| 永靖县| 呈贡县| 富民县| 廉江市| 洱源县| 汽车| 历史| 尼木县| 昌吉市| 武威市| 屯门区| 娄底市| 通许县| 丰镇市| 萨迦县| 商河县| 综艺| 临湘市| 日土县| 获嘉县| 敖汉旗| 彰化县| 惠安县| 阜新|