文章详情

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

请输入下面的图形验证码

提交验证

短信预约提醒成功

详解Java8 CompletableFuture的并行处理用法

2024-04-02 19:55

关注

前言

工作中你可能会遇到很多这样的场景,一个接口,要从其他几个service调用查询方法,分别获取到需要的值之后再封装数据返回。

还可能在微服务中遇到类似的情况,某个服务的接口,要使用好几次feign去调用其他服务的方法获取数据,最后拿到想要的值并封装返回给前端。

这样的场景下,当某个或多个rpc调用的方法比较耗时,整个接口的响应就会非常慢。Java8之后,有一个工具非常适合处理这种场景,就是CompletableFuture。

场景

本章主要讲解CompletableFuture的并行处理用法,来针对这种很常见的场景,帮助大家快速掌握并应用到实际工作当中。CompletableFuture内部的用法还有许多,但个人用到的场景大多都是并行处理,对其他场景感兴趣的小伙伴可以另行百度搜索。

场景说明:

写一个接口,调用另外两个HTTP接口,分别获取二十四节气和星座,最后放在一起返回。

用法

1、在线API

我们访问极速数据网站,注册一个账号,就可以免费使用里面的一些在线API,平均每天有100次免费机会,对于我这样经常本地做一些测试的人来说完全够用了。

这里,我使用了其中的查询二十四节气API,和查询星座API,后面会提供案例代码,也可以直接使用我的。

2、编写在线API查询

这里,我们在查询时,模拟耗时的情况。

1.查询二十四节气

package com.example.async.service;

import cn.hutool.http.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;


@Service
@Slf4j
public class TwentyFourService {

   public static final String APPKEY = "xxxxxx";// 你的appkey
   public static final String URL = "https://api.jisuapi.com/jieqi/query";

   public String getResult() {
       String url = URL + "?appkey=" + APPKEY;
       String result = HttpUtil.get(url);

       // 模拟耗时
       try {
          TimeUnit.SECONDS.sleep(5);
       } catch (Exception e) {
          log.error("[二十四节气]>>>> 异常: {}", e.getMessage(), e);
       }

       return result;
   }
   
}

2.查询星座

package com.example.async.service;

import cn.hutool.http.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;


@Service
@Slf4j
public class ConstellationService {
   public static final String APPKEY = "xxxxxx";// 你的appkey
   public static final String URL = "https://api.jisuapi.com/astro/all";

   public String getResult() {

      String url = URL + "?appkey=" + APPKEY;
      String result = HttpUtil.get(url);

      // 模拟耗时
      try {
         TimeUnit.SECONDS.sleep(5);
      } catch (Exception e) {
         log.error("[星座]>>>> 异常: {}", e.getMessage(), e);
      }

      return result;
   }
   
}

3、编写查询服务

package com.example.async.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;


@Service
@Slf4j
public class QueryService {
   private final TwentyFourService twentyFourService;
   private final ConstellationService constellationService;

   public QueryService(TwentyFourService twentyFourService, ConstellationService constellationService) {
      this.twentyFourService = twentyFourService;
      this.constellationService = constellationService;
   }

   
   public Map<String, Object> query() {
      // 1、查询二十四节气
      String twentyFourResult = twentyFourService.getResult();

      // 2、查询星座
      String constellationResult = constellationService.getResult();

      // 3、返回
      Map<String, Object> map = new HashMap<>();
      map.put("twentyFourResult", twentyFourResult);
      map.put("constellationResult", constellationResult);
      return map;
   }
}

4、编写测试接口

这里,我们专门加上了耗时计算。

package com.example.async.controller;

import cn.hutool.core.date.TimeInterval;
import com.example.async.service.QueryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;


@RestController
@RequestMapping("/api")
@Slf4j
public class TestController {

   private final QueryService queryService;

   public TestController(QueryService queryService) {
      this.queryService = queryService;
   }

   
   @GetMapping("/query")
   public ResponseEntity<Map<String, Object>> query() {
      // 计时
      final TimeInterval timer = new TimeInterval();
      timer.start();
      Map<String, Object> map = queryService.query();
      map.put("costTime", timer.intervalMs() + " ms");
      return ResponseEntity.ok().body(map);
   }
}

5、效果

可以看到,两个接口一共耗费了10秒左右才返回。

6、CompletableFuture并行查询

现在我们来使用CompletableFuture改造下接口,并行查询两个HTTP接口再返回。

package com.example.async.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;


@Service
@Slf4j
public class QueryService {
   private final TwentyFourService twentyFourService;
   private final ConstellationService constellationService;

   public QueryService(TwentyFourService twentyFourService, ConstellationService constellationService) {
      this.twentyFourService = twentyFourService;
      this.constellationService = constellationService;
   }

   
   public Map<String, Object> queryAsync() {

      Map<String, Object> map = new HashMap<>();

      // 1、查询二十四节气
      CompletableFuture<String> twentyFourQuery = CompletableFuture.supplyAsync(twentyFourService::getResult);
      twentyFourQuery.thenAccept((result) -> {
         log.info("查询二十四节气结果:{}", result);
         map.put("twentyFourResult", result);
      }).exceptionally((e) -> {
         log.error("查询二十四节气异常: {}", e.getMessage(), e);
         map.put("twentyFourResult", "");
         return null;
      });

      // 2、查询星座
      CompletableFuture<String> constellationQuery = CompletableFuture.supplyAsync(constellationService::getResult);
      constellationQuery.thenAccept((result) -> {
         log.info("查询星座结果:{}", result);
         map.put("constellationResult", result);
      }).exceptionally((e) -> {
         log.error("查询星座异常: {}", e.getMessage(), e);
         map.put("constellationResult", "");
         return null;
      });

      // 3、allOf-两个查询必须都完成
      CompletableFuture<Void> allQuery = CompletableFuture.allOf(twentyFourQuery, constellationQuery);
      CompletableFuture<Map<String, Object>> future = allQuery.thenApply((result) -> {
         log.info("------------------ 全部查询都完成 ------------------ ");
         return map;
      }).exceptionally((e) -> {
         log.error(e.getMessage(), e);
         return null;
      });

      // 获取异步方法返回值
      // get()-内部抛出了异常需手动处理; join()-内部处理了异常无需手动处理,点进去一看便知。
      future.join();

      return map;
   }
}

7、编写测试接口

package com.example.async.controller;

import cn.hutool.core.date.TimeInterval;
import com.example.async.service.QueryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;


@RestController
@RequestMapping("/api")
@Slf4j
public class TestController {

   private final QueryService queryService;

   public TestController(QueryService queryService) {
      this.queryService = queryService;
   }

   
   @GetMapping("/queryAsync")
   public ResponseEntity<Map<String, Object>> queryAsync() {
      // 计时
      final TimeInterval timer = new TimeInterval();
      timer.start();
      Map<String, Object> map = queryService.queryAsync();
      map.put("costTime", timer.intervalMs() + " ms");
      return ResponseEntity.ok().body(map);
   }
}

8、CompletableFuture效果

可以看到,时间缩短了一倍。

思考

如果在微服务中,有一个很复杂的业务需要远程调用5个第三方laji厂家的接口,每个接口假设都耗时5秒,使用CompletableFuture并行处理最终需要多久?

答案是肯定的,同步查询需要25秒左右,CompletableFuture并行处理还是5秒左右,也就是说,同一个接口中,调用的耗时接口越多,CompletableFuture优化的幅度就越大。

示例代码

可以下载我的完整示例代码本地按需测试,里面有我的极速数据API的key,省得自己注册账号了,每天免费就100次,先到先得哦。

到此这篇关于详解Java8 CompletableFuture的并行处理用法的文章就介绍到这了,更多相关Java8 CompletableFuture内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

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

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

软考中级精品资料免费领

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

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

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

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

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

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

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