参考一篇写的非常好的博客戳这里
一、背景
JDK1.5中对线程获取结果进行了很大的优化,具体可以参考我以前的博客戳这里,但是针对多线程结果其实还是通过无限循环,或者 阻塞的方式来获取的,很不友好,比如Rxjava已经实现了利用观察者模式,完成后通过回调来获取结果。所以在jdk1.8中增加了类CompletableFuture来对Future进行增强。
二、简单实用
2.1、创建异步应用
CompletableFuture.supplyAsync(()->{
sleep(60000);
System.out.println("线程:"+Thread.currentThread().getName()+"调用了supplyAsync");
return "zhw";
})
利用函数式编程来实现或比较简单、明了。supplyAsync内部中自动创建一个线程池。当然你可以可以指定线程池。
下面是默认线程池的代码:
/**
* Default executor -- ForkJoinPool.commonPool() unless it cannot
* support parallelism.
*/
private static final Executor asyncPool = useCommonPool ?
ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
利用jdk1.7中的ForkJoinPool线程池来执行任务,无需关系线程池的创建和销毁,只需关系具体的业务,增加了开发效率。
runAsyn也可以完成创建,不过参数不同,还是supplyAsync更实用
public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
特点:
- 如果以Async结尾的方法,都是另起一个新线程异步执行。否则都是和上个调用在同一个线程中执行,适用于大部分方法,必须下面的Apply、Accept、whenComplete方法等等
2.2、Apply对结果进一步处理
supplyAsync方法和CompletableFuture里面大多方法都是返回一个新的CompletableFuture引用,这是链式调用的基础
CompletableFuture.supplyAsync(()->{
sleep(60000);
System.out.println("线程:"+Thread.currentThread().getName()+"调用了supplyAsync");
return "zhw";
}).thenApplyAsync(x->{
System.out.println("线程:"+Thread.currentThread().getName()+"调用了thenApply");
return x+" hellow word";
});
比如thenApplyAsync,这个方法从字面看出另起一个线程,thenApply就是同步调用。
上面中apply中的方法都是利用上面的结果作为入参,然后对结果再次处理加工,比如supplyAsync返回"zhw",然后在thenApplyAsync方法中"zhw"作为参数传入,这样上面整个结果就是"zhw hellow word".
下面是我的总结
CompletableFuture中方法 | 函数式接口 |
---|---|
Apply | Function |
2.3、Accept对结果纯消费
他和Apply方法的不同就是更新consumer
CompletableFuture中方法 | 函数式接口 |
---|---|
Apply | Consumer |
上个链式的结果都是Apply、accept方法的入参。
2.4、whenComplete获取结果
public static void testWhenComplete() throws Exception{
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(BasicMain::getMoreData);
Future<Integer> f = future.whenComplete((v, e) -> {
System.out.println(v);
System.out.println(e);
});
System.out.println(f.get());
}
whenComplete有两个参数,第一个是正常的结果,第二个e是异常。其中还有handle方法,这个其实就是whenComplete+Apply,两个方法的组合
2.5、结果联合
两个不想干的方法调用,可以同时开始,然后在将两个结果进行合并返回
CompletableFuture
.supplyAsync(()->{
log.debug("supplyAsync1");
sleep(2000);
return "zhw";
})
.thenCombineAsync(CompletableFuture.supplyAsync(()->{
log.debug("supplyAsync2");
sleep(2000);
return " hellow ";
}),(s1,s2)->{
log.debug("thenCombineAsync");
return s1+s2;
})
比如上面两个方法各自需要2s,如果同步处理需要4s结束,但是这样处理后只需要2s就返回结果。
目前也只看到两个结果进行联合,感觉还是有限制,不如Rxjava方便。