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

Java CompletableFuture使用方式

 更新時間:2024年07月04日 10:02:37   作者:xindoo  
這篇文章主要介紹了Java CompletableFuture使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

在我之前的文章IO密集型服務(wù)提升性能的三種方法中提到過,提升IO密集型應(yīng)用性能有個方式就是異步編程,實現(xiàn)異步時一定會用到Future,使用多線程+Future我們可以讓多個任務(wù)同時去執(zhí)行,最后統(tǒng)一去獲取執(zhí)行結(jié)果,這樣整體執(zhí)行的時長就取決于最長的一個任務(wù),比如如下代碼:

public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        System.out.println(new Date());
        Future<String> future1 = executorService.submit(() -> {
            Thread.sleep(5000);
            return new Date() + ":" + "thread1 result";
        });
        Future<String> future2 = executorService.submit(() -> {
            Thread.sleep(3000);
            return new Date() + ":" + "thread2 result";
        });
        try {
            System.out.println(future1.get());
            System.out.println(future2.get());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

上面代碼的運行時長是5s,如果兩個任務(wù)串行執(zhí)行的化,運行時間就會是8s,當(dāng)多個任務(wù)多線程異步執(zhí)行時,最終總的執(zhí)行時長取決于最長任務(wù)的執(zhí)行時長。Future在大部分異步變成情況下,已經(jīng)能很好的滿足我們異步變成的訴求了,但當(dāng)我看到CompletableFuture這個東西的時候,才發(fā)現(xiàn)Future還是太簡單,我還是太年輕。

CompletableFuture除了和Future一樣可以獲取執(zhí)行結(jié)果外,它還**簡化了異常、提供了手動設(shè)置結(jié)果的接口、鏈?zhǔn)讲僮?、結(jié)果組合、回調(diào),**接下來我們通過一些代碼示例,來看下CompletableFuture這些特性如何吊打Future。

異常處理

在使用Future時,你只能在get()的時候抓取到異常,異常處理會和結(jié)果獲取的邏輯混在一起,有些時候處理起來會比較麻煩,而CompletableFuture提供了exceptionallyhandle 兩個api,可以很方便的添加異常處理邏輯,后續(xù)只需要直接使用get獲取結(jié)果即可,代碼示例如下:

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            // 故意拋出一個異常
            if (System.currentTimeMillis() % 2 == 0) {
                throw new RuntimeException("Exception occurred!");
            }
            return "Result";
        }, executorService);

        future = future.exceptionally(ex -> {
            // 對異常進(jìn)行處理,并提供一個異常時的結(jié)果
            return "Default Value";
        });

        try {
            System.out.println(future.get()); // 輸出 "Default Value"
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

exceptionally api讓任務(wù)在運行過程中,如果抓到了Exception,就可以調(diào)用你給定的邏輯來處理異常。

與exceptionally就是handle方法,達(dá)到的效果一致,但使用略有不同,可以看出handle這個api是在任務(wù)執(zhí)行完成后,講exception和執(zhí)行結(jié)果共同處理一次。

        future = future.handle((result, ex) -> {
            if (ex != null) {
                return "Default Value";
            }
            return result;
        });
        try {
            System.out.println(future.get()); // 輸出 "Default Value"
        } catch (Exception e) {
            e.printStackTrace();
        }

手動設(shè)置結(jié)果

Future中,我們無法手動地完成一個任務(wù)或者設(shè)置任務(wù)的結(jié)果,這個任務(wù)的執(zhí)行結(jié)果完全取決于任務(wù)的執(zhí)行情況。

但在CompletableFuture,我們可以在任何時間點上手動設(shè)置結(jié)果或者標(biāo)記任務(wù)為已完成。

舉個例子,我要通過接口獲取某個數(shù)據(jù),但很要求時效性,如果超過1s我就不要接口調(diào)用結(jié)果了,而是返回一個默認(rèn)值。

Future設(shè)置等待時間也可以實現(xiàn)類似的功能,但不是很直觀, CompletableFuture就很簡單直觀了。

public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                // 隨機sleep 0-2s
                Thread.sleep(ThreadLocalRandom.current().nextInt(2000));
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "Result";
        }, executorService);
        CompletableFuture<String> finalFuture = future;
        // 1s后手動完成
        executorService.submit(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 手動地完成這個 CompletableFuture,并設(shè)置計算結(jié)果
            finalFuture.complete("Default Value");
        });

        try {
            System.out.println(future.get()); // 概率性輸出 "Default Value"
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

鏈?zhǔn)讲僮?/h2>

鏈?zhǔn)讲僮饕馕吨憧梢詫⒁粋€CompletableFuture的結(jié)果直接傳遞給另一個異步操作,而無需等待第一個操作完成。

這使得你可以更容易地編寫復(fù)雜的并發(fā)邏輯,這種非常適合需要將多個接口結(jié)果串起來的流程,有點像langChain,我們直接看示例代碼:

public static void main(String[] args) {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            // 第一個異步任務(wù)
            return "Hello";
        }).thenApplyAsync(result -> {
            // 第二個異步任務(wù),依賴第一個任務(wù)的結(jié)果
            return result + " World";
        }).thenApplyAsync(result -> {
            // 第三個異步任務(wù),依賴第二個任務(wù)的結(jié)果
            return result + "!";
        });
        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

這個示例比較簡單,在實際使用中,我們可以將三個任務(wù)替換成任何需要相互依賴的任務(wù),你只需要定義每個任務(wù)的輸入和輸出,然后將它們連接在一起,就可以創(chuàng)建一個復(fù)雜的并發(fā)流程。

結(jié)果組合

CompletableFuture提供了幾個方法來組合或合并多個CompletableFuture的結(jié)果。

最常用的可能是thenCombineallOf方法。

以下是thenCombine方法的使用示例:

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
    return "Hello";
});

CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
    return "World!";
});

CompletableFuture<String> combinedFuture = future1.thenCombine(future2, (s1, s2) -> {
    return s1 + ", " + s2;
});

try {
    String result = combinedFuture.get();
    System.out.println(result); // 輸出 "Hello, World!"
} catch (InterruptedException | ExecutionException e) {
    e.printStackTrace();
}

在上述代碼中,我們首先創(chuàng)建了兩個獨立的CompletableFuture,然后使用thenCombine方法將它們的結(jié)果組合在一起。

以下是allOf方法的使用示例:

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
    return "Hello";
});

CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
    return "World!";
});

CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2);

// 當(dāng)所有的 CompletableFuture 都完成時,獲取結(jié)果
allFutures.thenRun(() -> {
    try {
        String result1 = future1.get();
        String result2 = future2.get();
        System.out.println(result1 + ", " + result2); // 輸出 "Hello, World!"
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }
});

可以看出thenCombine和allOf都實現(xiàn)了類似的功能,但兩者的側(cè)重點不同,thenCombine實現(xiàn)的是對執(zhí)行結(jié)果的聚合,而allOf實現(xiàn)的是對執(zhí)行完狀態(tài)的聚合,還是需要你去顯式調(diào)用get()方法去獲取結(jié)果的,所以你還是得根據(jù)具體需求來選擇使用thenCombine還是allOf。

回調(diào)

使用Future時,我們只能通過get()或者isDone()方法來獲取到任務(wù)是否執(zhí)行完成了,無法讓任務(wù)執(zhí)行完成后主動通知到我們,但CompletableFuture提供了一些回調(diào)方法,可以讓任務(wù)執(zhí)行完成后執(zhí)行結(jié)果處理的任務(wù)或者執(zhí)行一些通知的邏輯。

CompletableFuture提供了幾個方法來設(shè)置回調(diào),如thenApply, thenAccept, 和 thenRun。

具體看代碼示例:

public static void main(String[] args) {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            // 異步任務(wù)
            return "Hello, World!";
        });

        future.thenApply(result -> {
            // 當(dāng) future 完成時,這個回調(diào)會被調(diào)用。
            // result 參數(shù)是 future 的結(jié)果。
            // 這個回調(diào)的結(jié)果會被包裝成一個新的 CompletableFuture。
            return result.length();
        }).thenAccept(length -> {
            // 當(dāng)前面的 CompletableFuture 完成時,這個回調(diào)會被調(diào)用。
            // length 參數(shù)是前面 CompletableFuture 的結(jié)果。
            // 這個回調(diào)沒有返回值。
            System.out.println(length); // 輸出 "Hello, World!" 的長度
        }).thenRun(() -> {
            // 當(dāng)前面的 CompletableFuture 完成時,這個回調(diào)會被調(diào)用。
            // 這個回調(diào)沒有輸入?yún)?shù),也沒有返回值。
            System.out.println("Done");
        });
    }

thenApply、thenAccept和thenRun都是在任務(wù)執(zhí)行完成后被調(diào)起,但他們定位有所不同,thenApply處理的結(jié)果可以被包裝成一個新的CompletableFuture,只后可以繼續(xù)鏈?zhǔn)秸{(diào)用。

但thenAccept只能接受輸入,無法提供輸出,所以他的定位是任務(wù)的收尾,比如可以將結(jié)果輸出。

而thenRun既沒有輸入也沒有輸出,所以它只是獲取到了任務(wù)執(zhí)行完的狀態(tài),任務(wù)的執(zhí)行結(jié)果是獲取不到的,所以它是最弱的。

總結(jié)

總結(jié)下本文,Future 盡管有用,但在功能上還是相對簡單。

CompletableFuture不僅提供了獲取執(zhí)行結(jié)果的能力,它還增添了異常處理、手動完成、鏈?zhǔn)讲僮?、結(jié)果組合和回調(diào)等強大功能。

  • 異常處理: 利用exceptionallyhandle方法,可以簡化異常處理流程,使其更加直觀和易于管理。
  • 手動設(shè)置結(jié)果: CompletableFuture允許我們在任意時間點手動設(shè)置結(jié)果,增加了靈活性。
  • 鏈?zhǔn)讲僮?/strong>: 通過鏈?zhǔn)讲僮?,我們可以將不同的異步操作以流水線的方式串聯(lián)起來,編寫復(fù)雜的并發(fā)邏輯變得更加簡單。
  • 結(jié)果組合: thenCombineallOf方法能夠?qū)⒍鄠€CompletableFuture的結(jié)果合并,為我們提供了更多處理異步操作結(jié)果的方式。
  • 回調(diào): 提供了thenApply, thenAccept, 和 thenRun等方法,允許我們在任務(wù)完成后進(jìn)行結(jié)果處理或其他邏輯操作。

通過這些特性,CompletableFuture顯著地提升了異步編程的能力和靈活性。無論是簡化異常處理,還是實現(xiàn)復(fù)雜的異步邏輯,CompletableFuture都能夠幫助我們寫出更清晰、更高效的代碼。我相信通過本文的示例代碼,你可以更深入地理解CompletableFuture的強大之處,并在你的項目中充分利用它來提升性能。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot?2.5.5整合輕量級的分布式日志標(biāo)記追蹤神器TLog的詳細(xì)過程

    SpringBoot?2.5.5整合輕量級的分布式日志標(biāo)記追蹤神器TLog的詳細(xì)過程

    分布式追蹤系統(tǒng)是一個最終的解決方案,如果您的公司已經(jīng)上了分布式追蹤系統(tǒng),這篇文章主要介紹了SpringBoot?2.5.5整合輕量級的分布式日志標(biāo)記追蹤神器TLog,需要的朋友可以參考下
    2022-10-10
  • 使用Spring boot 的profile功能實現(xiàn)多環(huán)境配置自動切換

    使用Spring boot 的profile功能實現(xiàn)多環(huán)境配置自動切換

    這篇文章主要介紹了使用Spring boot 的profile功能實現(xiàn)多環(huán)境配置自動切換的相關(guān)知識,非常不錯,具有一定的參考借鑒價值 ,需要的朋友可以參考下
    2018-11-11
  • SpringCloud Eureka搭建的方法步驟

    SpringCloud Eureka搭建的方法步驟

    這篇文章主要介紹了SpringCloud Eureka搭建的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • 基于servlet實現(xiàn)統(tǒng)計網(wǎng)頁訪問次數(shù)

    基于servlet實現(xiàn)統(tǒng)計網(wǎng)頁訪問次數(shù)

    這篇文章主要為大家詳細(xì)介紹了基于servlet實現(xiàn)統(tǒng)計網(wǎng)頁訪問次數(shù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • 基于SpringBoot+Redis實現(xiàn)一個簡單的限流器

    基于SpringBoot+Redis實現(xiàn)一個簡單的限流器

    在Spring?Boot中使用Redis和過濾器實現(xiàn)請求限流,過濾器將在每個請求到達(dá)時檢查請求頻率,并根據(jù)設(shè)定的閾值進(jìn)行限制,這樣可以保護您的應(yīng)用程序免受惡意請求或高并發(fā)請求的影響,本文我們通過Spring?Boot?+Redis?實現(xiàn)一個輕量級的消息隊列,需要的朋友可以參考下
    2023-08-08
  • Mybatis環(huán)境搭建和使用實例代碼

    Mybatis環(huán)境搭建和使用實例代碼

    MyBatis 是一款優(yōu)秀的持久層框架,它支持定制化 SQL、存儲過程以及高級映射。本文重點給大家介紹Mybatis的環(huán)境搭建和使用實例代碼,需要的朋友參考下吧
    2017-12-12
  • Java獲取任意http網(wǎng)頁源代碼的方法

    Java獲取任意http網(wǎng)頁源代碼的方法

    這篇文章主要介紹了Java獲取任意http網(wǎng)頁源代碼的方法,可實現(xiàn)獲取網(wǎng)頁代碼以及去除HTML標(biāo)簽的代碼功能,涉及Java正則操作相關(guān)實現(xiàn)技巧,需要的朋友可以參考下
    2017-09-09
  • java生成隨機字符串的兩種方法

    java生成隨機字符串的兩種方法

    這篇文章主要為大家詳細(xì)介紹了java生成隨機字符串的兩種方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • Java Fluent Mybatis 聚合查詢與apply方法詳解流程篇

    Java Fluent Mybatis 聚合查詢與apply方法詳解流程篇

    Java中常用的ORM框架主要是mybatis, hibernate, JPA等框架。國內(nèi)又以Mybatis用的多,基于mybatis上的增強框架,又有mybatis plus和TK mybatis等。今天我們介紹一個新的mybatis增強框架 fluent mybatis關(guān)于聚合查詢、apply方法詳解
    2021-10-10
  • 分布式Netty源碼分析概覽

    分布式Netty源碼分析概覽

    這篇文章主要為大家介紹了分布式Netty源碼分析概覽,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03

最新評論

进贤县| 巩义市| 乌恰县| 平顶山市| 师宗县| 汝南县| 万荣县| 木兰县| 中西区| 鹰潭市| 象山县| 玉环县| 永州市| 临西县| 汉沽区| 江西省| 讷河市| 赤水市| 元阳县| 永济市| 达尔| 平武县| 沙坪坝区| 游戏| 瑞昌市| 乌拉特后旗| 河南省| 凌源市| 新竹市| 涪陵区| 白玉县| 沁水县| 巴彦淖尔市| 湄潭县| 房产| 肇庆市| 宜兰市| 辽中县| 青龙| 岗巴县| 忻城县|