1.Future类介绍2.Future类介绍3.CompletableFuture类介绍4.CompletableFuture类的使用5.总结1.Future类介绍这篇文章JAVA并发编程-Callable接口和FutureTask的介绍和使用说Future是一个可以获取返回值的异步处理线程类。以前无论是继承Thread类还是实现Runnable接口,都无法获取到线程的返回值,而Future可以。Future是一个有返回值的线程。这样一来,我们可能就看不懂了。让我们用一个生产案例来说明这个例子。2.Future类的使用假设我们现在有这样一个需求:我们先来看一个页面:这是在网上找到的一个数据大屏的图片,如果要查询返回这个屏幕的数据,你会怎么做??我们知道大屏显示的区域不一样,要查询的业务逻辑也不一样。可以分为以下几个区域:如果你现在是新手,可以一次查询一个区域。检查完2区,再检查3区,再返回前端,这样效率不高。改进方法:多区同步查询,最后统一返回前端(多支箭齐射)。这个还是比较抽象的,我们用一张图来举例:这张图应该可以说明,接下来我们用Future类来展示代码:新数据结果();//查询区域1FutureTaskallHumanNum=newFutureTask<>(()->queryHumanNum());//使用线程池执行CalculateThreadPoolConfig.getThreadPoolExecutor().submit(allDoctorNum);//查询区域2FutureTaskallMaleNum=newFutureTask<>(()->queryAllMaleNum());//使用线程池执行CalculateThreadPoolConfig.getThreadPoolExecutor().submit(queryInvitedDoctorNum);//以此类推//……//拼接结果集result.setAllHumanNum(allHumanNum.get(5,TimeUnit.SECONDS));result.setAllMaleNum(allMaleNum.get(5,TimeUnit.SECONDS));返回结果;}可以看出,无论我们查询多少个数据集,只查询时间最长的那个数据集的时间就足够了,实现了同步并行查询的效果,大大减少了查询时间。但是我们要注意这行代码:allHumanNum.get(5,TimeUnit.SECONDS);get的意思是一直阻塞返回结果,但是加上数字和单位就意味着只等待5秒,否则会抛出异常。我们在工作的时候,如果我们需要调用别人的接口返回数据,但是又不知道对方要计算多长时间,说不定对方的接口会拖累我们写的整个函数。为了避免这种情况,为了在工作中保护自己,我们需要学会加一层保险。如果对方的界面在五秒内没有返回,就已经过时了。3、CompletableFuture类的介绍介绍了前面的FutreTask类。我们知道虽然这是一个非常有用的类,但是它也有很多缺点,比如:1.get()容易阻塞2.如果要将多个结果集合并成一个结果集需要很多FutureTask3.FutureTask只能用于单步简单计算,不能将两个异步计算合并为一个异步计算。这两个异步计算相互独立,第二个依赖第二个。一个的结果。4.当Future集合中的一个任务最快结束时,返回结果。还有很多不足,这时候我们可以使用CompletableFuture这个类!CompletableFuture弥补了Future模式的不足。可以将多个结果集合并为一个结果集,可以把一个异步任务分成几个阶段进行计算,后面的结果依赖前面的结果等等。总而言之,CompletableFuture可以做到FutureTask可以做到的,CompletableFuture可以多做!我们先搜索CompletableFuture类,它实现了Future接口和CompletionStage接口。CompletionStage:表示异步计算过程中的某个阶段。一个阶段完成后,可能会触发另一个阶段。让我们仔细看看CompletionStage拥有的方法。根据thenApply、whenComplete、exceptionally等方法,我们可以大致看出这个类可以对一个计算的各个阶段进行编程。先执行一个步骤,(根据thenApply)再执行下一步,(whenComplete)运行完会怎样,(exceptionally)抛出异常会怎样,等等。好像是链式调用,这就是所谓的链式编程。接下来我们通过一个案例来实战使用CompletableFuture。4、CompletableFuture类的使用假设我们现在有一个电商比价的需求:我们要采集各大网站Thinkinjava这本书的价格,开多线程采集各大网站,并输出信息to在控制台中,线程执行后也会输出信息,请使用CompletableFuture和链式编程来解决。接下来开始编程:publicclassCompletableFutureNextMallDemo{//这是需要采集的价格网站staticListlist=Arrays.asList(newNetMall("jd"),newNetMall("pdff"),newNetMall("tmall"),newNetMall("xhs"),newNetMall("xy"),newNetMall("zh"),newNetMall("sf"));}classNetMall{//这是具体类网站的价格计算方法privateStringmallName;publicNetMall(){}publicNetMall(StringmallName){this.mallName=mallName;}publicStringgetMallName(){returnmallName;}publicvoidsetMallName(StringmallName){this.mallName=mallName;}//计算价格的方法publicdoublecalcPrice(StringproductName){try{//假设这是计算过程Thread.sleep(1000);}catch(InterruptedExceptione){e.printStackTrace();}返回ThreadLocalRandom。current().nextDouble()*2+productName.charAt(0);}}最关键执行方法//链式调度多个箭头一起publicstaticListgetPriceByASync(Listlist,StringproductName){//循环遍历所有网站,每个网站启动一个线程进行计算//CompletableFuture.supplyAsync代表执行过程返回值相当于Future的get(0方法returnlist.stream().map(netMall->CompletableFuture.supplyAsync(()->{returnString.format(productName+"in%spriceis%.2f",netMall.getMallName(),netMall.calcPrice(productName));}//第一步完成后,第二步输出书的价格).thenApply(r->{System.out.println(r);returnr;}//任务完成后输出网站计算完成).whenComplete((v,e)->{System.out.println(netMall.getMallName()+"Completion!");}//当抛出异常时,输出异常).exceptionally(e->{System.out.println("Getfailed,anexceptionoccurred!");e.printStackTrace();returnnull;})).collect(Collectors.toList()).stream()//最后统一调用join方法返回result.map(CompletableFuture::join)//最后合并成一个List并作为result返回。collect(Collectors.toList());}这里我们抽取CompletableFuture,发现代码会是这样的:CompletableFuture.supplyAsync()//执行有返回值的异步处理,相当于FutureTask的get().thenApply()//然后执行第二步。whenComplete()//完成时触发的逻辑。Exceptionally();//异常发生时触发逻辑5.小结通过今天的学习,我们了解了Future和CompletableFuture的基本理论和实践。这些本身就是两个非常有用的类。希望我们在工作中能多用到它们,但不要盲目使用多线程,因为多用了一种工具,就多了一种风险