CompletableFuture是java8中引入的机制,为了弥补异步执行时Future机制的不足。
那么光是用Future会有什么问题?
主要是无法做到回调机制以及多任务的协同。
CompletableFuture实现了CompletionStage接口,提供了多种任务协同的回调方法,使得异步回调写起来很方便。
其实future和completableFuture都是异步编程的模式,前者是需要主动获取结果的,后者是回调。
1 创建
@Test
public void testCreate() throws ExecutionException, InterruptedException {
CompletableFuture<Void> c1 = CompletableFuture.runAsync(() -> {
System.out.println("runAsync");
});
CompletableFuture<String> c2 = CompletableFuture.supplyAsync(() -> "supplyAsync");
System.out.println(c2.get());
ExecutorService service = Executors.newFixedThreadPool(10);
CompletableFuture<Void> c3 = CompletableFuture.runAsync(() -> {
System.out.println("runAsync");
}, service);
CompletableFuture<String> c4 = CompletableFuture.supplyAsync(() -> "supplyAsync", service);
System.out.println(c4.get());
}
提供了四种api,两个角度:是否有返回值;是否指定线程池(默认和指定)。
2 转换
@Test
public void testTransfer() {
CompletableFuture.supplyAsync(() -> 1)
.thenApply(i -> 1 + 1)
.thenAccept(i -> {
System.out.println(i);
});
CompletableFuture.supplyAsync(() -> 1).thenRun(() -> {
System.out.println("thenRun");
});
}
其实就是最基本的异步回调,主要有三种:
apply:转换;
accept:消耗;
run:无参消耗;
每一种都有同步和异步两种,异步又分为指定线程池和默认线程池。
后面所有的api都支持这种分类。
3 结合
@Test
public void testCombine() throws ExecutionException, InterruptedException {
int r = CompletableFuture.supplyAsync(() -> 1).thenCombine(CompletableFuture.supplyAsync(() -> 2), (i, j) -> i + j).get();
Assert.assertTrue(r == 3);
}
@Test
public void testMany() throws InterruptedException, ExecutionException {
List<CompletableFuture<Integer>> jobs = Lists.newArrayList(
CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 1;
}),
CompletableFuture.supplyAsync(() -> {
return 2;
})
);
CompletableFuture.allOf(
jobs.toArray(new CompletableFuture[jobs.size()])
).thenRun(()->{
int result = jobs.stream().map(c-> {
try {
int tt = c.get();
System.out.println();
return tt;
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
return -99;
}
}).reduce(0, (sum, i)->sum+i);
System.out.println(result);
});
System.out.println("#########");
int result2 = (int) CompletableFuture.anyOf(
jobs.toArray(new CompletableFuture[jobs.size()])
).get();
System.out.println(result2);
Thread.sleep(10000);
}
combine可以结合两个任务;
allOf执行完所有的任务才返回,后面需要遍历全部的job来自行获取结果;
anyOf执行完其中任意一个就返回。
异常
@Test
public void testException() throws ExecutionException, InterruptedException {
CompletableFuture r = CompletableFuture.supplyAsync(()->{
throw new RuntimeException();
}).exceptionally(e->{
System.out.println(e);
return 1;
});
}
正常基于future的多线程,如果有异常,执行时不会报错,只会在主动get时报错。
completableFuture可以使用exceptionally里面对异常进行一次补救。