CompletableFuture异步编程
CompletableFuture异步编程
前言
基础讲解:同步和异步
同步:提交请求->等待服务器处理->处理完返回 期间客户端浏览器等待
异步:请求通过事件触发->服务器处理(无需等待)->处理完毕
提示:以下是本篇文章正文内容,下面案例可供参考
一、CompletableFuture运算范式
二、RemoteLoader.Java
2.1 、LabelService.JAVA
三、Test
串行流示例
3.1五个调用五个接口!延时1秒
并行流示例
四、CompletableFuture基本使用
CompletableFuture<String> future = new CompletableFuture<>();
new Thread(() -> {
try {
future.complete("Finish"); //任务执行完成后 设置返回的结果
} catch (Exception e) {
log.error("CompletableFuture -> 任务线程出现异常", e);
}
}).start();
System.out.println(future.join()); //获取任务线程返回的结果
4.1、exceptionally方法
4.1.1、exceptionally -> 回调异常处理
4.1.1.2、示例
/*Java8不仅提供允许任务返回结果的supplyAsync,还提供了没有返回值的runAsync;
让我们可以更加的关注业务的开发,不需要处理异常错误的管理*/
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
return "Future";
}).exceptionally(throwable -> "Throwable exception message:" + throwable.getMessage());
System.out.println(future.get());
4.2、allOf方法
假如我们要调用多个CompletableFuture,想计算包含关键字CompletableFuture结果的数量。可以使用CompletableFuture.allOf()达成目的。
List<String> webPageLinks = Arrays.asList(...) // A list of
List<CompletableFuture<String>> pageContentFutures = webPageLinks.stream()
.map(webPageLink -> downloadWebPage(webPageLink))
.collect(Collectors.toList());
CompletableFuture<Void> allFutures = CompletableFuture.allOf(
pageContentFutures.toArray(new CompletableFuture[pageContentFutures.size()])
);
五、 CompletableFuture 测试
5.1、 注:CompletableFuture -> 注意阻塞
5.2 、join()方法
5.2.1 join()方法和get()方法非常类似,这唯一不同的地方是如果最顶层的CompletableFuture完成的时候发生了异常,它会抛出一个未经检查的异常
/*
*使用异步计算处理调用接口方法
*/
List<CompletableFuture<String>> completableFutureList = remoteLoaders.stream().map(
loader ->
CompletableFuture.supplyAsync(loader::load)).collect(toList());
/*
*当所有future完成的时候,我们调用了future.join(),因此我们不会在任何地方阻塞。
* */
List<String> customerDetail = completableFutureList
.stream()
.map(CompletableFuture::join)
.collect(toList());
System.out.println(customerDetail);
long end = System.currentTimeMillis();
System.out.println("总共花费时间:" + (end - start));
5.3、 结果
5.4、自定义线程 newFixedThreadPool
/*自定义线程池,优化CompletableFuture
使用并行流无法自定义线程池,但是CompletableFuture可以*/
long start = System.currentTimeMillis();
List<RemoteLoader> remoteLoaders = Arrays.asList(
new RemoteLoader.CustomerInfoService(),
new RemoteLoader.WatchRecordService(),
new RemoteLoader.OrderService(),
new RemoteLoader.LabelService(),
new RemoteLoader.LearnRecordService()
);
/*线程自定义*/
ExecutorService executorService = Executors.newFixedThreadPool(50);
List<CompletableFuture<String>> completableFutureList = remoteLoaders.
stream().map(
loader -> CompletableFuture.supplyAsync(
loader::load,
executorService)).
collect(toList());
/*上述已经讲过这个stream的作用了*/
List<String> customerDetail = completableFutureList.
stream().
map(CompletableFuture::join).
collect(toList());
System.out.println(customerDetail);
long end = System.currentTimeMillis();
System.out.println("总共花费时间:" + (end - start));
总结
这两者如何选择主要看任务类型,建议如果你的任务是计算密集型的,并且没有I/O操作的话,那么推荐你选择Stream的并行流。
实现简单并行效率也是最高的如果你的任务是有频繁的I/O或者网络连接等操作,那么推荐使用CompletableFuture。
采用自定义线程池的方式,根据服务器的情况设置线程池的大小,尽可能的让CPU忙碌起来