一、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