文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

聊聊 JDK8 的 CompletableFuture ,你明白了吗?

2024-12-02 00:07

关注

CompletableFuture

CompletableFuture是java.util.concurrent库在java 8中新增的主要工具,同传统的Future相比,其支持流式计算、函数式编程、完成通知、自定义异常处理等很多新的特性。

supplyAsync方法

通过该函数创建的CompletableFuture实例会异步执行当前传入的计算任务。在调用端,则可以通过get或join获取最终计算结果。

这个有两个不同的实现方式,一种是我们传入我们自己创建的线程池,然后使用我们创建的线程池进行操作,还有一种就是不传线程池,让程序是使用默认的线程池进行操作。

//使用默认线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
return asyncSupplyStage(asyncPool, supplier);
}
//使用自定义线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor) {
return asyncSupplyStage(screenExecutor(executor), supplier);
}

第一种只需传入一个Supplier实例(一般使用lamda表达式),此时框架会默认使用ForkJoin的线程池来执行被提交的任务。

我们来自定义一个代码看一下:

ExecutorService executors = Executors.newFixedThreadPool(5);

CompletableFuture<List<Order>> bFuture = CompletableFuture.supplyAsync(() -> {
//执行查询
QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("userId",params.getUserId());
queryWrapper.eq("SHOP_ID",params.getShopId());
List<Order> list = orderService.list(queryWrapper);
return list;
}, executors);

当我们执行查询的时候,这时候实际上就属于异步的查询的,我们可以写多个查询,比如,上面的代码我们查询的是订单,下面我们可以查询用户的信息,还是使用同样的线程池。

       CompletableFuture<List<User>> aFuture = CompletableFuture.supplyAsync(() -> {
//执行查询
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("SHOP_ID",params.getShopId());
List<User> list = userService.list(queryWrapper);
return list;
}, executors);

这时候,我们就可以获取一下这个返回的结果,那么获取返回结果我们需要调用什么方法呢?

可以通过get或join获取最终计算结果。这时候我们可以打印一下,获取结果的长度。

List<User> list = aFuture.get();
List<Order> list = bFuture.get();

这样,我们就可以使用异步查询来完成我们对结果集的查询。

这就有小伙伴想问,如果我想要用第一个的结果,去在第二个数据中去查询,我们应该怎么做呢?

thenApply

thenApply提交的任务类型需遵从Function签名,也就是有入参和返回值,其中入参为前置任务的结果。

什么意思呢?其实很简单,我们这里直接看代码:

    CompletableFuture<List<Order>> cFuture = bFuture.thenApply((list) -> {
List<String> collect = list.stream().map(User::getUserId).collect(Collectors.toList());
...
return orderList;
});

这实际上,就是我们根据查询出的所有用户的集合,直接获取到他的userId,然后我们根据UserId,把这些用户下的订单数据都提取出来,当然,在实际使用中,我们理论上可以无限连接后续计算任务,从而实现链条更长的流式计算。

但是这种链式也不是都非常的好用,毕竟要控制住线程池,大家记得在使用完成之后,可以把自己创建的线程池小回调,调用shutDown方法就可以了。我们再接着往下说。

thenAccept

实际上thenAccept的效果,和thenApply 的效果等同,但是thenAccept提交的任务类型需遵从Consumer签名,也就是有入参但是没有返回值,其中入参为前置任务的结果。

实际上调用的是和之前一样的,但是就是没有返回值了。

 CompletableFuture<void> cFuture = bFuture.thenAccept((list) -> {
List<String> collect = list.stream().map(User::getUserId).collect(Collectors.toList());
...

});

这就是区别,不需要进行返回了,这种一般用的地方比较特殊,就比如说我们执行了很多操作,但是在其中需要夹杂一些比如说给某个服务进行通知,但是我们并不需要这个服务给我们返回值的结果的时候,实际上完全可以使用这种方式。方便还快捷。当然,你想直接调用,阿粉也是没有意见的。

whenComplete

whenComplete主要用于注入任务完成时的回调通知逻辑。这个解决了传统future在任务完成时,无法主动发起通知的问题。前置任务会将计算结果或者抛出的异常作为入参传递给回调通知函数。

这个方法就是相当于是把前一个任务中的结果,通过第二个方法获取结果,也并不会影响第二个的逻辑。

示例代码如下:

CompletableFuture<List<Order>> listCompletableFuture = bFuture.whenComplete((r, e) -> {
if (e != null) {
System.out.println("compute failed!");
} else {
System.out.println("received result is " + r);
}
});

实际上最后答应的就是接受者的信息。大家学会了么?

来源:Java极客技术内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯