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

Java中的CompletableFuture原理與用法

 更新時(shí)間:2024年01月15日 15:05:21   作者:曠野歷程  
CompletableFuture 是由Java8引入的,這讓我們編寫清晰可讀的異步代碼變得更加容易,該類功能比Future 更加強(qiáng)大,在Java中CompletableFuture用于異步編程,異步通常意味著非阻塞,運(yùn)行任務(wù)單獨(dú)的線程,與主線程隔離,這篇文章介紹CompletableFuture原理與用法,一起看看吧

CompletableFuture 是由Java8引入的,這讓我們編寫清晰可讀的異步代碼變得更加容易,該類功能比Future 更加強(qiáng)大。

什么是 CompletableFuture

在Java中CompletableFuture用于異步編程,異步通常意味著非阻塞,運(yùn)行任務(wù)單獨(dú)的線程,與主線程隔離。并且通過(guò)回調(diào)可以在主線程中得到異步任務(wù)的執(zhí)行狀態(tài),是否完成和異常等信息。

通過(guò)這種方式,主線程不會(huì)被阻塞,不需要一直等到子線程完成。主線程可以并行的執(zhí)行其他任務(wù)。使用這種并行方式,可以極大的提高程序的性能。

為什么要引入 CompletableFuture

一些業(yè)務(wù)場(chǎng)景我們需要使用多線程異步執(zhí)行任務(wù),加快任務(wù)執(zhí)行速度,所以 JDK5 新增了 Future 接口,用于描述一個(gè)異步計(jì)算的結(jié)果。

雖然 Future 以及相關(guān)使用方法提供了異步執(zhí)行任務(wù)的能力,但是對(duì)于結(jié)果的獲取卻是很不方便,我們必須使用 Future.get 的方式阻塞調(diào)用線程,或者使用輪詢方式判斷 Future.isDone 任務(wù)是否結(jié)束,再獲取結(jié)果。

Future<String> future = executor.submit(()->{
       Thread.sleep(2000);
       return "hello world";
});
// 獲取結(jié)果
System.out.println(future.get());

從上面的形式看來(lái)不能及時(shí)地得到計(jì)算結(jié)果,所以要實(shí)現(xiàn)真正的異步,上述這樣是完全不夠的。

若需要更強(qiáng)大的異步處理能力,單純使用 Future 接口或者 FutureTask 類并不能很好地完成以下業(yè)務(wù)場(chǎng)景:

  • 將兩個(gè)異步計(jì)算合并為一個(gè),這兩個(gè)異步計(jì)算之間相互獨(dú)立,同時(shí)第二個(gè)又依賴于第一個(gè)的結(jié)果;
  • 等待Future集合種的所有任務(wù)都完成;
  • 僅等待Future集合種最快結(jié)束的任務(wù)完成(有可能因?yàn)樗麄冊(cè)噲D通過(guò)不同的方式計(jì)算同一個(gè)值),并返回它的結(jié)果;
  • 通過(guò)編程方式完成一個(gè)Future任務(wù)的執(zhí)行(即以手工設(shè)定異步操作結(jié)果的方式);
  • 應(yīng)對(duì)Future的完成時(shí)間(即當(dāng)Future的完成時(shí)間完成時(shí)會(huì)收到通知,并能使用Future的計(jì)算結(jié)果進(jìn)行下一步的的操作,不只是簡(jiǎn)單地阻塞等待操作的結(jié)果)。

所以JDK 8.0新增了CompletableFuture 來(lái)解決上述這些痛點(diǎn)。

Future vs CompletableFuture

CompletableFuture 是 Future API的擴(kuò)展。

Future 被用于作為一個(gè)異步計(jì)算結(jié)果的引用。提供一個(gè) isDone() 方法來(lái)檢查計(jì)算任務(wù)是否完成。當(dāng)任務(wù)完成時(shí),get() 方法用來(lái)接收計(jì)算任務(wù)的結(jié)果。

Future 的局限性

不能手動(dòng)完成

當(dāng)你寫了一個(gè)函數(shù),用于通過(guò)一個(gè)遠(yuǎn)程API獲取一個(gè)電子商務(wù)產(chǎn)品最新價(jià)格。因?yàn)檫@個(gè) API 太耗時(shí),你把它允許在一個(gè)獨(dú)立的線程中,并且從你的函數(shù)中返回一個(gè) Future?,F(xiàn)在假設(shè)這個(gè)API服務(wù)宕機(jī)了,這時(shí)你想通過(guò)該產(chǎn)品的最新緩存價(jià)格手工完成這個(gè)Future 。你會(huì)發(fā)現(xiàn)無(wú)法這樣做。

Future 的結(jié)果在非阻塞的情況下,不能執(zhí)行更進(jìn)一步的操作

Future 不會(huì)通知你它已經(jīng)完成了,它提供了一個(gè)阻塞的 get() 方法通知你結(jié)果。你無(wú)法給 Future 植入一個(gè)回調(diào)函數(shù),當(dāng) Future 結(jié)果可用的時(shí)候,用該回調(diào)函數(shù)自動(dòng)的調(diào)用 Future 的結(jié)果。

多個(gè) Future 不能串聯(lián)在一起組成鏈?zhǔn)秸{(diào)用

有時(shí)候你需要執(zhí)行一個(gè)長(zhǎng)時(shí)間運(yùn)行的計(jì)算任務(wù),并且當(dāng)計(jì)算任務(wù)完成的時(shí)候,你需要把它的計(jì)算結(jié)果發(fā)送給另外一個(gè)長(zhǎng)時(shí)間運(yùn)行的計(jì)算任務(wù)等等。你會(huì)發(fā)現(xiàn)你無(wú)法使用 Future 創(chuàng)建這樣的一個(gè)工作流。

不能組合多個(gè) Future 的結(jié)果

假設(shè)你有10個(gè)不同的Future,你想并行的運(yùn)行,然后在它們運(yùn)行未完成后運(yùn)行一些函數(shù)。你會(huì)發(fā)現(xiàn)你也無(wú)法使用 Future 這樣做。

沒(méi)有異常處理

Future API 沒(méi)有任務(wù)的異常處理結(jié)構(gòu)居然有如此多的限制,幸好我們有CompletableFuture,你可以使用 CompletableFuture 達(dá)到以上所有目的。

CompletableFuture 實(shí)現(xiàn)了 Future  和 CompletionStage 接口,并且提供了許多關(guān)于創(chuàng)建,鏈?zhǔn)秸{(diào)用和組合多個(gè) Future 的便利方法集,而且有廣泛的異常處理支持。

CompletableFuture的應(yīng)用場(chǎng)景

  • 執(zhí)行比較耗時(shí)的操作時(shí),尤其是那些依賴一個(gè)或多個(gè)遠(yuǎn)程服務(wù)的操作,使用異步任務(wù)可以改善程序的性能,加快程序的響應(yīng)速度。
  • 使用CompletableFuture類,它提供了異常管理的機(jī)制,讓你有機(jī)會(huì)拋出、管理異步任務(wù)執(zhí)行種發(fā)生的異常。
  • 如果這些異步任務(wù)之間相互獨(dú)立,或者他們之間的的某一些的結(jié)果是另一些的輸入,你可以講這些異步任務(wù)構(gòu)造或合并成一個(gè)。

CompletableFuture設(shè)計(jì)思想

CompletableFuture 按照類似“觀察者模式”的設(shè)計(jì)思想,原理分析可以從“觀察者”和“被觀察者”兩個(gè)方面著手。

由于回調(diào)種類多,但結(jié)構(gòu)差異不大,所以這里單以一元依賴中的thenApply為例,不再枚舉全部回調(diào)類型,如下圖所示:

被觀察者

  • 每個(gè)CompletableFuture都可以被看作一個(gè)被觀察者,其內(nèi)部有一個(gè)Completion類型的鏈表成員變量stack,用來(lái)存儲(chǔ)注冊(cè)到其中的所有觀察者。當(dāng)被觀察者執(zhí)行完成后會(huì)彈棧stack屬性,依次通知注冊(cè)到其中的觀察者。上面例子中步驟fn2就是作為觀察者被封裝在UniApply中。
  • 被觀察者CF中的result屬性,用來(lái)存儲(chǔ)返回結(jié)果數(shù)據(jù)。這里可能是一次RPC調(diào)用的返回值,也可能是任意對(duì)象,在上面的例子中對(duì)應(yīng)步驟fn1的執(zhí)行結(jié)果。

觀察者

CompletableFuture支持很多回調(diào)方法,例如thenAccept、thenApply、exceptionally等,這些方法接收一個(gè)函數(shù)類型的參數(shù)f,生成一個(gè)Completion類型的對(duì)象(即觀察者),并將入?yún)⒑瘮?shù)f賦值給Completion的成員變量fn,然后檢查當(dāng)前CF是否已處于完成狀態(tài)(即result!=null),如果已完成直接觸發(fā)fn,否則將觀察者Completion加入到CF的觀察者鏈stack中,再次嘗試觸發(fā),如果被觀察者未執(zhí)行完則其執(zhí)行完畢之后通知觸發(fā)。

  • 觀察者中的dep屬性:指向其對(duì)應(yīng)的CompletableFuture,在上面的例子中dep指向CF2。
  • 觀察者中的src屬性:指向其依賴的CompletableFuture,在上面的例子中src指向CF1。
  • 觀察者Completion中的fn屬性:用來(lái)存儲(chǔ)具體的等待被回調(diào)的函數(shù)。這里需要注意的是不同的回調(diào)方法(thenAccept、thenApply、exceptionally等)接收的函數(shù)類型也不同,即fn的類型有很多種,在上面的例子中fn指向fn2。

CompletableFuture核心功能

CompletableFuture的功能主要體現(xiàn)在它的CompletionStage,如下圖所示:

CompletionStage接口定義了任務(wù)編排的方法,執(zhí)行某一階段,可以向下執(zhí)行后續(xù)階段,可以實(shí)現(xiàn)如下功能:

  • 轉(zhuǎn)換(thenCompose)
  • 組合(thenCombine)
  • 消費(fèi)(thenAccept)
  • 運(yùn)行(thenRun)
  • 帶返回的消費(fèi)(thenApply)

具體其他功能大家可以根據(jù)需求自行查看。

CompletableFuture創(chuàng)建使用

創(chuàng)建CompletableFuture對(duì)象,提供了四個(gè)靜態(tài)方法用來(lái)創(chuàng)建CompletableFuture對(duì)象:

public static CompletableFuture<Void>   runAsync(Runnable runnable)
public static CompletableFuture<Void>   runAsync(Runnable runnable, Executor executor)
public static <U> CompletableFuture<U>  supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U>  supplyAsync(Supplier<U> supplier, Executor executor)

Asynsc 表示異步,而 supplyAsync 與 runAsync 不同在與前者異步返回一個(gè)結(jié)果,后者是 void。第二個(gè)函數(shù)第二個(gè)參數(shù)表示是用我們自己創(chuàng)建的線程池,否則采用默認(rèn)的 ForkJoinPool.commonPool() 作為它的線程池.其中Supplier是一個(gè)函數(shù)式接口,代表是一個(gè)生成者的意思,傳入0個(gè)參數(shù),返回一個(gè)結(jié)果。

CompletableFuture<String> future = CompletableFuture.supplyAsync(()->{
    return "hello world";
});
//阻塞的獲取結(jié)果  ''helllo world"
System.out.println(future.get());

CompletableFuture用法詳解

沒(méi)有返回值的異步任務(wù)

如果你想異步的運(yùn)行一個(gè)后臺(tái)任務(wù)并且不需要任務(wù)返回結(jié)果,就可以使用 runAsync()。

runAsync() 返回一個(gè)新的 CompletableFuture,它在運(yùn)行給定操作后由在 ForkJoinPool.commonPool() 運(yùn)行的任務(wù)異步完成。

/**
 * 沒(méi)有返回值的異步任務(wù)
 */
@Test
public void runAsync() throws Exception {
    CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
        log.info("Current thread name: {}", Thread.currentThread().getName());
        // 模擬長(zhǎng)時(shí)間運(yùn)行的作業(yè)
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        };
    });
    // 主線程阻塞
    future.get();
    System.out.println("主線程結(jié)束");
}

有返回值的異步任務(wù)

當(dāng)運(yùn)行一個(gè)異步任務(wù)并且需要有返回結(jié)果時(shí),就可以使用 supplyAsync()。

CompletableFuture.supplyAsync() 它持有 supplier<T> 并且返回 CompletableFuture<T>,T 是通過(guò)調(diào)用傳入的 supplier 取得的值的類型。

CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
    @Override
    public String get() {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
        return "Success";
    }
});
System.out.println(future.get());

Supplier<T> 是一個(gè)簡(jiǎn)單的函數(shù)式接口,表示 supplier 的結(jié)果。它有一個(gè) get(),該方法可以寫入你的后臺(tái)任務(wù)中,并且返回結(jié)果。

還可以使用 lambda 表達(dá)式使得上面的示例更加簡(jiǎn)明:

/**
 * 有返回值的異步任務(wù)
 */
@Test
public void supplyAsync() throws Exception {
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        log.info("Current thread name: {}", Thread.currentThread().getName());
        // 模擬長(zhǎng)時(shí)間運(yùn)行的作業(yè)
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        };
        return "Success";
    });
    // 主線程阻塞
    System.out.println(future.get());
}

上述 runAsync() 和 supplyAsync() 都是在單獨(dú)的線程中執(zhí)行他們的任務(wù),但在實(shí)際業(yè)務(wù)中我們不會(huì)只創(chuàng)建一個(gè)線程。

自定義線程池執(zhí)行方法

CompletableFuture 可以從全局的 ForkJoinPool.commonPool() 獲得一個(gè)線程中執(zhí)行這些任務(wù)。但也可以創(chuàng)建一個(gè)線程池并傳給 runAsync() 和 supplyAsync() 來(lái)讓他們從線程池中獲取一個(gè)線程執(zhí)行它們的任務(wù)。

CompletableFuture API 的所有方法都有兩個(gè)變體-一個(gè)接受Executor作為參數(shù),另一個(gè)不這樣:

static CompletableFuture<Void>  runAsync(Runnable runnable)
static CompletableFuture<Void>  runAsync(Runnable runnable, Executor executor)
static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)

創(chuàng)建一個(gè)線程池,并傳遞給其中一個(gè)方法:

Executor executor = Executors.newFixedThreadPool(10);
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
        throw new IllegalStateException(e);
    }
    return "Success";
}, executor);

線程串行化

由于 CompletableFuture.get() 方法是阻塞的,它會(huì)一直等到 Future 完成,并且在完成后返回結(jié)果。但是,這是我們想要的嗎?對(duì)于構(gòu)建異步系統(tǒng),我們應(yīng)該附上一個(gè)回調(diào)給 CompletableFuture,當(dāng) Future 完成的時(shí)候,自動(dòng)的獲取結(jié)果。

如果不想等待結(jié)果返回,就可以把需要等待 Future 完成執(zhí)行的邏輯寫入到回調(diào)函數(shù)中。

可以使用 thenApply()、thenAccept() 、thenRun() 回調(diào)給 CompletableFuture。

thenApply()

當(dāng)一個(gè)線程依賴另一個(gè)線程時(shí),可以使用 thenApply() 來(lái)把這兩個(gè)線程串行化。

thenApply:可以使用 thenApply() 處理和改變 CompletableFuture 的結(jié)果。

/**
 * 使用 thenApply() 處理和改變CompletableFuture的結(jié)果
 *
 * @throws Exception
 */
@Test
public void thenApply1() throws Exception {
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        return "Java";
    }).thenApply(o -> {
        return "Hello " + o;
    });
    System.out.println(future.get());
}

thenAccept()

如果你不想從你的回調(diào)函數(shù)中返回任何東西,僅僅想在 Future 完成后運(yùn)行一些代碼片段,你可以使用 thenAccept() 和 thenRun(),這些方法經(jīng)常在調(diào)用鏈的最末端的最后一個(gè)回調(diào)函數(shù)中使用。

thenAccept:消費(fèi)處理結(jié)果,接收任務(wù)的處理結(jié)果,并消費(fèi)處理,無(wú)返回結(jié)果。

@Test
public void thenAccept() throws Exception {
    CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
        // 模擬長(zhǎng)時(shí)間運(yùn)行的作業(yè)
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
        return "Success";
    }).thenAccept(o -> {
        if ("Success".equals(o)) {
            // 模擬長(zhǎng)時(shí)間運(yùn)行的作業(yè)
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
        }
    });
    future.get();
    log.info("======================");
    System.out.println("結(jié)束.");
}

thenRun()

thenRun() 不能訪 Future 的結(jié)果,它持有一個(gè) Runnable 返回 CompletableFuture:

@Test
public void thenRun() throws Exception {
    CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
        // 模擬長(zhǎng)時(shí)間運(yùn)行的作業(yè)
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
        return "Success";
    }).thenRun(() -> {
        // 作業(yè)完成后執(zhí)行一些代碼片段
        System.out.println("thenRun 執(zhí)行一些代碼片段");
    });
    future.get();
}

結(jié)果合并

thenCompose()

使用 thenCompose() 合并兩個(gè)有依賴關(guān)系的 CompletableFutures 的執(zhí)行結(jié)果。

private static Integer num = 10;
@Test
public void thenCompose() throws Exception {
    //第一步加 10
    CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
        System.out.println("讓num+10;任務(wù)開(kāi)始");
        num += 10;
        return num;
    });
    //合并
    CompletableFuture<Integer> future1 = future.thenCompose(i ->
            //再來(lái)一個(gè) CompletableFuture
            CompletableFuture.supplyAsync(() -> i + 1)
    );
    System.out.println(future.get());
    System.out.println(future1.get());
}

thenCombine()

使用 thenCombine() 組合兩個(gè)獨(dú)立的 future。當(dāng)兩個(gè)獨(dú)立的 Future 都完成的時(shí)候使用 thenCombine() 用來(lái)做一些事情。

@Test
public void thenCompose() throws Exception {
    // 長(zhǎng)方形:S=長(zhǎng)*寬
    //第一步加 10
    CompletableFuture<Integer> lengthFuture = CompletableFuture.supplyAsync(() -> {
        return 50;
    });
    CompletableFuture<Integer> widthFuture = CompletableFuture.supplyAsync(() -> {
        return 30;
    });
    CompletableFuture<Integer> combinedFuture = lengthFuture.thenCombine(widthFuture, (t1, t2) -> {
        System.out.println(t1);
        System.out.println(t2);
        return t1 * t2;
    });
    System.out.println(combinedFuture.get());
}

合并多個(gè)任務(wù)的結(jié)果

使用 thenCompose() 和 thenCombine() 可以把兩個(gè) CompletableFuture 組合在一起。如果要是想組合任意數(shù)量的 CompletableFuture,應(yīng)該怎么做?

可以使用 allOf 和 anyOf 組合任意多個(gè) CompletableFuture。這兩個(gè)函數(shù)都是靜態(tài)函數(shù),參數(shù)是變長(zhǎng)的 CompletableFuture 的集合。

allOf 和 anyOf 的區(qū)別,前者是「與」,后者是「或」。

allOf()

allOf 的返回值是 CompletableFuture<Void> 類型,這是因?yàn)槊總€(gè)傳入的 CompletableFuture 的返回值都可能不同,所以組合的結(jié)果是 無(wú)法用某種類型來(lái)表示的,索性返回 Void 類型。那么,如何獲取每個(gè) CompletableFuture 的執(zhí)行結(jié)果呢?

例子: 并行地下載 N 個(gè)資源,待下載完成之后,并資源額外處理。

@Test
public void allOf() throws Exception {
    // URL 列表集合
    List<String> webLinks = Arrays.asList("https://www.baidu.com/", "https://www.bing.com/", "https://www.so.com/");
    // 并行下載多個(gè)網(wǎng)頁(yè)
    List<CompletableFuture<String>> contentFutureList = webLinks.stream().map(webLink -> downloadWebLink(webLink)).collect(Collectors.toList());
    // 通過(guò)allof,等待所有網(wǎng)頁(yè)下載完畢,收集返回結(jié)果
    CompletableFuture<Void> allFutures = CompletableFuture.allOf(contentFutureList.toArray(new CompletableFuture[contentFutureList.size()]));
    // 附上回調(diào)函數(shù),獲取結(jié)果集
    // 方式一
    CompletableFuture<List<String>> result = allFutures.thenApply(v -> contentFutureList.stream().map(o -> {
        try {
            return o.get();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }).collect(Collectors.toList()));
    System.out.println(result.get());
    // 方式二
    result = allFutures.thenApply(v -> contentFutureList.stream().map(CompletableFuture<String>::join).collect(Collectors.toList()));
    System.out.println(result.get());
}
private CompletableFuture<String> downloadWebLink(String webLink) {
    return CompletableFuture.supplyAsync(() -> {
        // 模擬下載過(guò)程
        System.out.println("開(kāi)始下載網(wǎng)頁(yè):" + webLink);
        return "這是一個(gè)網(wǎng)頁(yè)內(nèi)容";
    });
}

這里有個(gè)關(guān)鍵問(wèn)題,因?yàn)?allof 沒(méi)有返回值,所以通過(guò) theApply,給 allFutures 附上一個(gè)回調(diào)函數(shù)。在回調(diào)函數(shù)里面,以此調(diào)用么一個(gè) Future 的 Get() 函數(shù),獲取結(jié)果后存入 List<String> 中。

anyOf()

anyOf 的含義是只要有任意一個(gè) CompletableFuture 結(jié)束,就可以做接下來(lái)的事情,而無(wú)須像 allOf 那樣,等待所有的 CompletableFuture 結(jié)束。

但由于每個(gè) CompletableFuture 的返回值類型可能不同,意味著無(wú)法判斷是什么類型,所以 anyOf 的返回值是 CompletableFuture<Object> 類型。

@Test
public void anyOf() throws Exception {
    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return "future1 結(jié)果";
    });
    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return "future2 結(jié)果";
    });
    CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return "future3 結(jié)果";
    });
    CompletableFuture<Object> future = CompletableFuture.anyOf(future1, future2, future3);
    System.out.println(future.get());
}

在該例子中,因?yàn)?future1、future2、future3 的返回值都是 CompletableFuture<String>,所以anyOf 的返回的 Object 一定也是 String 類型。

并且在 3 個(gè) future 中,future3 睡眠時(shí)間最短,會(huì)最先執(zhí)行完成, anyOfFuture.get() 獲取的也就是 future3 的內(nèi)容。future1、future2 的返回結(jié)果會(huì)被丟棄。

異常處理

在調(diào)用 supplyAsync() 任務(wù)中發(fā)生一個(gè)錯(cuò)誤,這時(shí)候沒(méi)有任何 thenApply 會(huì)被調(diào)用并且 future 將以一個(gè)異常結(jié)束。如果在第一個(gè) thenApply() 發(fā)生錯(cuò)誤,這時(shí)候第二個(gè)和第三個(gè)將不會(huì)被調(diào)用,同樣的,future 將以異常結(jié)束。

exceptionally()

回調(diào)處理異常,從原始Future中生成的錯(cuò)誤恢復(fù)的機(jī)會(huì)。

@Test
public void exceptionally() throws Exception {
    Integer age = -1;
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        if (age < 0) {
            throw new IllegalArgumentException("年齡不能為負(fù)數(shù)");
        }
        return "張三";
    }).exceptionally(ex -> {
        System.out.println(ex.getMessage());
        return "Unknown!";
    });
    System.out.println(future.get());
}

handle()

從異?;謴?fù),無(wú)論一個(gè)異常是否發(fā)生它都會(huì)被調(diào)用。

@Test
public void handle() throws Exception {
    Integer age = -1;
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        if (age < 0) {
            throw new IllegalArgumentException("年齡不能為負(fù)數(shù)");
        }
        return "張三";
    }).handle((res, ex) -> {
        if (ex != null) {
            System.out.println(ex.getMessage());
            return "Unknown!";
        }
        return res;
    });
    System.out.println(future.get());
}

如果異常發(fā)生 res 參數(shù)將是 null,否則 ex 將是 null。 

參考:CompletableFuture原理與用法詳解

到此這篇關(guān)于Java中的CompletableFuture原理與用法的文章就介紹到這了,更多相關(guān)java CompletableFuture內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot配置HTTPS的詳細(xì)步驟

    SpringBoot配置HTTPS的詳細(xì)步驟

    本文介紹了配置SpringBoot項(xiàng)目HTTPS的全流程,包括開(kāi)發(fā)環(huán)境生成自簽名證書和生產(chǎn)環(huán)境配置正式SSL證書,以及配置HTTP自動(dòng)跳轉(zhuǎn)HTTPS以提升用戶體驗(yàn),注意事項(xiàng)和常見(jiàn)問(wèn)題也一并進(jìn)行了說(shuō)明,需要的朋友可以參考下
    2026-03-03
  • mybatis使用pgvector的實(shí)現(xiàn)示例

    mybatis使用pgvector的實(shí)現(xiàn)示例

    本文主要介紹了mybatis定義和注冊(cè)VectorTypeHandler,并使用@TableName注解設(shè)置Entity類,其中autoResultMap屬性設(shè)置為true,這樣就可以實(shí)現(xiàn)數(shù)據(jù)存儲(chǔ)與查詢,感興趣的可以了解一下
    2026-01-01
  • 在SpringBoot中實(shí)現(xiàn)一個(gè)訂單號(hào)生成系統(tǒng)的示例代碼

    在SpringBoot中實(shí)現(xiàn)一個(gè)訂單號(hào)生成系統(tǒng)的示例代碼

    在Spring Boot中設(shè)計(jì)一個(gè)訂單號(hào)生成系統(tǒng),主要考慮到生成的訂單號(hào)需要滿足的幾個(gè)要求:唯一性、可擴(kuò)展性、以及可能的業(yè)務(wù)相關(guān)性,本文給大家介紹了幾種常見(jiàn)的解決方案及相應(yīng)的示例代碼,需要的朋友可以參考下
    2024-02-02
  • 阿里規(guī)范:為何boolean類型變量命名禁用is開(kāi)頭

    阿里規(guī)范:為何boolean類型變量命名禁用is開(kāi)頭

    這篇文章主要給大家介紹了關(guān)于阿里規(guī)范:為何boolean類型變量命名禁用is開(kāi)頭的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Java設(shè)計(jì)模式之初識(shí)行為型模式

    Java設(shè)計(jì)模式之初識(shí)行為型模式

    今天帶大家學(xué)習(xí)Java設(shè)計(jì)模式的相關(guān)知識(shí)點(diǎn),文中對(duì)Java行為型模式做了非常詳細(xì)的介紹及代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們很有幫助,需要的朋友可以參考下
    2021-06-06
  • Java判斷用戶名和密碼是否符合要求過(guò)程詳解

    Java判斷用戶名和密碼是否符合要求過(guò)程詳解

    這篇文章主要介紹了Java判斷用戶名和密碼過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Java類的初始化實(shí)踐分析

    Java類的初始化實(shí)踐分析

    這篇文章主要介紹了Java類的初始化,結(jié)合具體實(shí)例形式較為詳細(xì)的分析了java類初始化的常見(jiàn)情況、操作技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2019-07-07
  • spring mvc中@RequestBody注解的作用說(shuō)明

    spring mvc中@RequestBody注解的作用說(shuō)明

    這篇文章主要介紹了spring mvc中@RequestBody注解的作用說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • java通過(guò)注解翻譯字典的實(shí)現(xiàn)示例

    java通過(guò)注解翻譯字典的實(shí)現(xiàn)示例

    本文主要介紹了java通過(guò)注解翻譯字典的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • 淺析Java中如何實(shí)現(xiàn)線程之間通信

    淺析Java中如何實(shí)現(xiàn)線程之間通信

    本篇文章主要介紹了淺析Java中如何實(shí)現(xiàn)線程之間通信。針對(duì) Java 的線程間通信進(jìn)行了大致的講解,有興趣的可以了解一下
    2017-04-04

最新評(píng)論

公主岭市| 盐池县| 南部县| 屯昌县| 台南县| 乌鲁木齐县| 博客| 台中市| 井研县| 女性| 四会市| 盐池县| 高邮市| 孟津县| 汶川县| 长葛市| 平原县| 武川县| 伊通| 郁南县| 顺昌县| 安宁市| 台北市| 丹东市| 巍山| 印江| 贵德县| 长春市| 临夏县| 临沂市| 昌黎县| 长岛县| 泽库县| 山阴县| 新乡县| 隆子县| 涞源县| 鱼台县| 武功县| 桦甸市| 义乌市|