JAVA8之前的Future
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newCachedThreadPool();
Future<String> future = executorService.submit(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "callable finished";
});
//do something else
Thread.sleep(2000);
String callableResult = future.get();
System.out.println(callableResult);
}
CompletableFuture的優(yōu)勢
- 提供了異步程序執(zhí)行的另一種方式:回調(diào),不需要像future.get()通過阻塞線程來獲取異步結(jié)果或者通過isDone來檢測異步線程是否完成來執(zhí)行后續(xù)程序。
- 能夠管理多個(gè)異步流程,并根據(jù)需要選擇已經(jīng)結(jié)束的異步流程返回結(jié)果。
構(gòu)建CompletableFuture
構(gòu)造函數(shù)
/**
* Creates a new incomplete CompletableFuture.
*/
public CompletableFuture() {
}
純翻譯:構(gòu)建一個(gè)不完整的CompletableFuture,為什么說不完整呢,請(qǐng)往下看
式例1
public static class test{
public static String getTestResult()
{
int i = 10/0;
return "test";
}
}
public static void main(String[] args) {
CompletableFuture<String> completableFuture = new CompletableFuture();
new Thread(()->{
try {
completableFuture.complete(test.getTestResult());
} catch (Exception e) {
System.out.println("get exception in side");
completableFuture.completeExceptionally(e);
}
}).start();
try {
String result = completableFuture.get();
System.out.println(result);
} catch (Exception e) {
System.out.println("get exception out side");
e.printStackTrace();
}
}
一般需要complete() 設(shè)置異步線程可能返回的值,以及completeExceptionally() 向上拋出異常
工廠方法
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
Executor executor)
public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable,
Executor executor)
從入?yún)⒖梢钥吹剑珻ompletableFuture 允許我們自定義執(zhí)行器,在實(shí)際項(xiàng)目中我們可以選擇合適的線程池來提高異步程序的效率。
CompletableFuture completableFuture = CompletableFuture.supplyAsync(() ->
{
try {Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "test";
}
);
CompletableFuture 流
java8 流式處理在CompletableFuture 也得到了完美的體現(xiàn),流處理包含的中間操作,終端操作分別對(duì)應(yīng)CompletableFuture 中以thenAccept開頭返回CompletableFuture <Void>(也就是回調(diào))的實(shí)例方法。中間操作對(duì)應(yīng)thenApply,thenCompose等等返回非CompletableFuture <Void>的實(shí)例方法。
式例2
CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
return "test ";
}).thenApply(u -> {
System.out.println(Thread.currentThread().getName());
return u + "in thenApply first";
})
.thenCompose(u -> CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName());
return u + "in thenCompose second";
})
).thenAccept(u -> {
System.out.println(Thread.currentThread().getName());
System.out.println(u + "in thenAccept last");
});
ForkJoinPool.commonPool-worker-1
main
ForkJoinPool.commonPool-worker-1
main
test in thenApply firstin thenCompose secondin thenAccept last
可以看到默認(rèn)的異步線程池都是ForkJoinPool.commonPool,同步操作都在main線程中處理。
多說一句thenApply 和thenCompose的區(qū)別,thenCompose在調(diào)用外部接口返回CompletableFuture<>類型時(shí)更方便。
多個(gè)CompletableFuture任務(wù)的管理
現(xiàn)實(shí)應(yīng)用中可能同時(shí)存在多個(gè)異步任務(wù),有時(shí)候我們需要他們一起完成才能進(jìn)行下面的操作,有時(shí)候我們又只需要在存在一個(gè)結(jié)果的情況下就返回。
private static final Random random = new Random();
public static String randomDelay()
{
int delay = 500 + random.nextInt(2000);
try {
System.out.println(String.format("%s sleep in %d",Thread.currentThread().getName(),delay));
Thread.sleep(delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(String.format("%s sleep in %s",Thread.currentThread().getName(),"end"));
return Thread.currentThread().getName()+" return";
}
public static void main(String[] args) {
CompletableFuture [] futures = {CompletableFuture.supplyAsync(()->randomDelay()),
CompletableFuture.supplyAsync(()->randomDelay()),CompletableFuture.supplyAsync(()->randomDelay())};
CompletableFuture.allOf(futures).join();
System.out.println("all timeout process end");
}
ForkJoinPool.commonPool-worker-2 sleep in 1957
ForkJoinPool.commonPool-worker-3 sleep in 2097
ForkJoinPool.commonPool-worker-1 sleep in 2422
ForkJoinPool.commonPool-worker-2 sleep in end
ForkJoinPool.commonPool-worker-3 sleep in end
ForkJoinPool.commonPool-worker-1 sleep in end
all timeout process end
上段代碼展示了 CompletableFuture.allOf 的用法,可以看到所有的線程結(jié)束后打印了"all timeout process end",注意 allOf 接受的是數(shù)組類對(duì)象。如果把a(bǔ)llOf改為 anyOf
CompletableFuture [] futures = {CompletableFuture.supplyAsync(()->randomDelay()),
CompletableFuture.supplyAsync(()->randomDelay()),CompletableFuture.supplyAsync(()->randomDelay())};
System.out.println(CompletableFuture.anyOf(futures).get());
System.out.println("all timeout process end");
ForkJoinPool.commonPool-worker-2 sleep in 529
ForkJoinPool.commonPool-worker-3 sleep in 759
ForkJoinPool.commonPool-worker-1 sleep in 1750
ForkJoinPool.commonPool-worker-2 sleep in end
ForkJoinPool.commonPool-worker-2 return
all timeout process end
可以看到只有一個(gè)線程結(jié)束時(shí)結(jié)果已經(jīng)返回,另外CompletableFuture還提供了專為兩個(gè)任務(wù)處理的方法
acceptEither
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(()->randomDelay());
completableFuture.acceptEither(completableFuture.supplyAsync(()->randomDelay()),u-> System.out.println(u)).join();
ForkJoinPool.commonPool-worker-2 sleep in 935
ForkJoinPool.commonPool-worker-1 sleep in 2422
ForkJoinPool.commonPool-worker-2 sleep in end
ForkJoinPool.commonPool-worker-2 return
CompletableFuture 異常處理
除了在get的時(shí)候通過 try catch 處理異常,CompletableFuture 提供了更優(yōu)雅的方式 exceptionally()和 handle()。handle處理方法類似,都是把異常對(duì)象轉(zhuǎn)為我們所需要的其他類型對(duì)象,然后處理。
public static String getTestResult()
{
int i = 10/0;
return "test";
}
public static void main(String[] args) {
CompletableFuture<String> completableFuture = new CompletableFuture();
new Thread(()->{
try {
completableFuture.complete(getTestResult());
} catch (Exception e) {
System.out.println("get exception in side");
completableFuture.completeExceptionally(e);
}
}).start();
completableFuture.exceptionally(e->"we hava a exception"+e.getMessage())
.thenAccept(u-> System.out.println(u));
}
總結(jié)
有關(guān)CompletableFuture 大部分內(nèi)容已經(jīng)講完了,相信看了之后應(yīng)該都會(huì)用了吧!
更多的細(xì)節(jié)還是參考JAVA8官方文檔和源碼吧!
http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html