Java併發------JDK8 CompletableFuture

一、runAsync 和 supplyAsync

1、runAsync 的基本使用:無返回值,持有一個 Runnable 對象。

System.out.println("begin");
CompletableFuture.runAsync(() -> {
    try {
        System.out.println("before sleep");
        TimeUnit.MILLISECONDS.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("after sleep");
});
System.out.println("end");

異步任務會執行,但是主線程不回等待異步任務返回結果,也就是不會阻塞當前線程。

輸出結果:

begin
end
before sleep

2、supplyAsync 的基本使用:有返回值,持有一個 Supplier 對象。

System.out.println("begin");
CompletableFuture<Person> supplyAsync = CompletableFuture.supplyAsync(() -> {
    System.out.println("before sleep");
    try {
        TimeUnit.MILLISECONDS.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("after sleep");
    return new Person();
});
System.out.println("before supplyAsync");
Person person = supplyAsync.get();
System.out.println("after supplyAsync");
System.out.println("end");

只有在調用 get() 方法時,纔會執行異步任務,並且帶有阻塞當前線程的效果。

輸出結果:

begin
before supplyAsync
before sleep
after sleep
after supplyAsync
end

二、thenApply、thenAccept、thenRun

thenAccept、thenRun 這兩個方法一般在調用鏈的最末端使用,區別在於是否可以獲取前一個任務的返回值和自己是否返回值

方法名 是否可獲得前一個任務的返回值 是否有返回值
thenApply 能獲得
thenAccept 能獲得
thenRun 不可獲得
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "this is before");
CompletableFuture<String> future2 = future1.thenApply(obj -> obj + ",this is after");
System.out.println(future2.get());// this is before,this is after

CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "this is before");
future3.thenAccept(System.out::println);// this is before

CompletableFuture<String> future4 = CompletableFuture.supplyAsync(() -> "this is before");
future4.thenRun(() -> {System.out.println("this is after");});// this is after

輸出結果:

this is before,this is after
this is before
this is after

thenApply、thenAccept、thenRun 這三個方法都帶有一個後綴爲 Async 的方法

CompletableFuture<String> supplyAsync = CompletableFuture.supplyAsync(() -> {
    try {
        //TimeUnit.MILLISECONDS.sleep(1000);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return "supplyAsync thread is " + Thread.currentThread().getName();
});
CompletableFuture<String> thenApply = supplyAsync.thenApply(obj -> obj + ",thenAccept thread is " + Thread.currentThread().getName());
CompletableFuture<String> thenApplyAsync = thenApply.thenApplyAsync(obj -> obj + ",thenApplyAsync thread is " + Thread.currentThread().getName());
System.out.println(thenApplyAsync.get());

三、thenCompose 和 thenCombine

1、thenCompose():當第一個任務完成時纔會執行第二個操作。

CompletableFuture<String> thenCompose = CompletableFuture.supplyAsync(() -> "this is first")
                .thenCompose(obj -> CompletableFuture.supplyAsync(() -> obj + ",this is second"));
        System.out.println(thenCompose.get());

thenApply 也可以實現相似的功能,但是要 get() 兩次。

CompletableFuture<CompletableFuture<String>> thenApply = CompletableFuture.supplyAsync(() -> "this is first")
                .thenApply(obj -> CompletableFuture.supplyAsync(() -> obj + ",this is second"));
        System.out.println(thenApply.get().get());

輸出結果:

this is first,this is second

2、thenCombine():兩個異步任務全部完成時纔會執行某些操作。

CompletableFuture<String> first = CompletableFuture.supplyAsync(() -> "this is first");
CompletableFuture<String> second = CompletableFuture.supplyAsync(() -> {
    try {
        TimeUnit.MILLISECONDS.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "this is second";
});
CompletableFuture<String> thenCombine = first.thenCombine(second, (s1, s2) -> s1 + "," + s2);
System.out.println(thenCombine.get());

輸出結果:

this is first,this is second

四、allOf 和 join

CompletableFuture<String> first = CompletableFuture.supplyAsync(() -> {
    System.out.println("first start");
    try {
        TimeUnit.MILLISECONDS.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("first return");
    return "this is first";
});
CompletableFuture<String> second = CompletableFuture.supplyAsync(() -> {
    System.out.println("second start");
    try {
        TimeUnit.MILLISECONDS.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("second return");
    return "this is second";
});
CompletableFuture<Void> allOf = CompletableFuture.allOf(first, second);
allOf.join();
System.out.println("all return");

輸出結果:

first start
second start
second return
first return
all return

當線程 1 和線程2 都開始執行時,join 會帶有阻塞功能,會在兩條線程都執行完後才繼續向下執行。

五、exceptionally 和 handle

1、exceptionally 處理異常,並且可以自定義返回值。

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    int i = 10 / 0;
    return i + "";
}).exceptionally(e -> {
    System.out.println("出現異常:" + e);
    return e.getMessage();
}).thenApply(obj -> "result is " + obj);
System.out.println(future.get());

輸出結果:

出現異常:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
result is java.lang.ArithmeticException: / by zero

2、handle 同樣是處理異常,並且可以自定義返回值。與 exceptionally 區別就是,handle 無論發沒發生異常都會執行。另外就是 exceptionally 的自定義返回值類型必須與被處理的線程返回值一致,handle 不需要一致。

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    int i = 10 / 0;
    return i;
}).handle((result, e) -> {
    if (result == null) {
        System.out.println("出現異常:" + e);
        return e.getMessage();
    }
    return result;
}).thenApply(obj -> "result is " + obj);
System.out.println(future.get());

輸出結果:

出現異常:java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
result is java.lang.ArithmeticException: / by zero
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章