当前位置: 首页 > news >正文

异步编程——CompletableFuture用法详解

文章目录

  • 前言
  • 1. Future + 线程池
  • 2. 什么是CompletableFuture

前言

我们异步执行一个任务时,需要用线程池Executor去创建,有两种方式:

  • 如果不需要有返回值, 任务继承Thread类或实现Runnable接口;
  • 如果需要有返回值,任务实现Callable接口,调用Executorsubmit方法执行任务,再使用Future.get()获取任务结果。

当我们得到包含结果的Future时,我们可以使用get方法等待线程完成并获取返回值,但问题是Futureget()方法会阻塞主线程。并且当多个线程存在依赖组合的时候,使用同步组件CountDownLatch是比较麻烦的。

Java8新增的CompletableFuture类提供了非常强大的Future的扩展功能,提供了函数式编程的能力,可以通过回调的方式处理计算结果,并且提供了组合多个异步任务的方法。并且CompletableFuture是非阻塞性的,就是在主线程之外创建一个独立的线程,用以运行一个非阻塞的任务,然后将结果通知主线程。通过这种方式,主线程不用为了任务的完成而阻塞,极大提升了程序的性能。

1. Future + 线程池

Future是Java5引入的新接口,提供了异步并行计算的能力。如果主线程需要执行一个耗时的计算任务,我们就可以通过Future把这个任务放到异步线程中执行,主线程继续处理其他任务,处理完成后,再通过Future获取计算结果。

举个例子,假设我们有两个查询任务,一个查询运动员信息,一个查询运动员的荣誉信息。

public class PlayerInfo {private String name;private int age;}public class PlayerInfoService {public PlayerInfo getPlayerInfo() throws InterruptedException {Thread.sleep(300);//模拟调用耗时return new PlayerInfo("Kobe", 32);}}public class MedalInfo {private String medalCategory;private int medalNum;}public class MedalInfoService {public MedalInfo getMedalInfo() throws InterruptedException {Thread.sleep(500); //模拟调用耗时return new MedalInfo("MVP", 1);}}

使用Future+线程池的方式实现异步任务:

public class FutureTest {public static void main(String[] args) throws InterruptedException, ExecutionException {// 1. 创建线程池ExecutorService executorService = Executors.newFixedThreadPool(10);// 2. 任务加入线程池PlayerInfoService playerInfoService = new PlayerInfoService();MedalInfoService medalInfoService = new MedalInfoService();long startTime = System.currentTimeMillis();FutureTask<PlayerInfo> playerInfoFutureTask = new FutureTask<>(new Callable<PlayerInfo>() {@Overridepublic PlayerInfo call() throws Exception {return playerInfoService.getPlayerInfo();}});executorService.submit(playerInfoFutureTask);Thread.sleep(400);FutureTask<MedalInfo> medalInfoFutureTask = new FutureTask<>(new Callable<MedalInfo>(){@Overridepublic MedalInfo call() throws Exception {return medalInfoService.getMedalInfo();}});executorService.submit(medalInfoFutureTask);PlayerInfo playerInfo = playerInfoFutureTask.get();MedalInfo medalInfo = medalInfoFutureTask.get();System.out.println("总共用时" + (System.currentTimeMillis() - startTime) + "ms");// 3. 关闭线程池executorService.shutdown();}}

运行结果:

总共用时905ms

如果是在主线程串行执行的话,耗时大约为300+500+400=1200ms。可见,future+线程池的异步方式,提高了程序的执行效率。但是,Future对于结果的获取,只能通过阻塞或者轮询的方式得到任务的结果。

  • Future.get()就是阻塞调用,在线程获取结果之前get方法会一直阻塞。阻塞的方式和异步编程的设计理念相违背。
  • Future提供了一个isDone方法,可以在程序中轮询这个方法查询执行结果。轮询的方式会耗费CPU资源。

轮询——在计算机网络中,轮询(Polling)是一种通信方式,其中一个节点(通常是客户端)定期发送请求到另一个节点(通常是服务器)以获取数据或状态。这种方式的缺点在于,即使没有可用的数据,客户端也会持续不断地发送请求,这会消耗大量的CPU资源。此外,如果轮询的间隔设置得太短,可能会导致网络拥塞,甚至可能影响实时性。因此,轮询并不是一种高效的通信方式,特别是在需要高性能和低延迟的应用中。

2. 什么是CompletableFuture

http://www.lryc.cn/news/302397.html

相关文章:

  • Linux常用命令(不断更新)
  • C++ 浮点数二分 数的三次方根
  • 辽宁博学优晨教育科技有限公司视频剪辑培训专业之选
  • 数据转换成json格式
  • css3的var()函数
  • 武汉灰京文化展望未来游戏产业,科技创新引领全面升级的游戏体验
  • SOLIDWORKS Visualize 界面介绍
  • 负载均衡下webshell连接nginx解析漏洞、sql注入第一关
  • 养老项目技术架构和工程结构
  • 免费白嫖一个互联网创业者交流论坛,真香!
  • Zilliz Cloud 再发新版本:性能提升超 10 倍,AI 应用开发流程再简化!
  • 基于SpringBoot的高校竞赛管理系统
  • 【国产MCU】-CH32V307-通用定时器(GPTM)-编码模式与旋转编码器驱动
  • 国外高防服务器需要注意哪些方面
  • MySQL系列之索引入门(下)
  • IO进程:fread\fwrite图像拷贝,read\write文件拷贝,时间函数
  • 基于java的企业校园招聘平台的设计与实现
  • Rocky Linux网卡静态配置
  • 【C语言】通讯录(静态版本+动态版本)思路解析+完整源代码
  • spring boot自动装配及自动装配条件判断
  • LeetCode--2298. 周末任务计数
  • 从零开始学习Netty - 学习笔记 - NIO基础 - ByteBuffer: 简介和基本操作
  • Chatgpt润色文章“咒语”
  • 【OpenGL教程2】 简单案例介绍Python 中的 OpenGL
  • 评估方法:CMMI/能力成熟度模型集成
  • Gin框架: HTML模板渲染之配置与语法详解
  • .NET Core WebAPI中使用Log4net 日志级别分类并记录到数据库
  • Day36 贪心算法 part05
  • C#计算矩形面积:通过定义结构 vs 通过继承类
  • 【复现】Panalog大数据日志审计系统 RCE漏洞_51