码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • CompletableFuture异步任务编排


    业务场景:

    查询详情页的逻辑比较多,有些数据还需要远程调用,必然要花费更多的时间。

    1、获取SKU的基本信息 0.5s

    2、获取SKU的图片信息 0.5s

    3、获取SKU的促销信息 1s

    4、获取SPU的所有销售属性 1s

    5、获取SPU的详情 1.5s

    假如商品详情页的每个查询,如果如上标注的时间才能完成,那么用户需要4.5秒的时间,才能够看到商品详情页面的内容,很显然是不能够接受的。

    如果有多个线程同时完成这6步操作,也许仅仅1.5秒就能够完成。

    4 5 需要1的返回结果。

    completableFuture简单调用

    1、简单调用

    1. //测试异步任务
    2. public static void main(String[] args) throws ExecutionException, InterruptedException {
    3. System.out.println("main .... start");
    4. CompletableFuture completableFuture = CompletableFuture.runAsync(() -> {
    5. System.out.println("当前线程:" + Thread.currentThread().getId());
    6. int i = 10 / 2;
    7. System.out.println("运行结果:" + i);
    8. }, pool);
    9. System.out.println("main ... end");
    10. }

     

    2、runAsync

    没有返回结果的方法调用:

     

    3、supplyAsync

    有返回结果的方法调用:无论是否get操作,使用了改操作,就是阻塞式等待。

    1. CompletableFuture future = CompletableFuture.supplyAsync(() -> {
    2. System.out.println("当前线程:" + Thread.currentThread().getId());
    3. int i = 10 / 2;
    4. System.out.println("运行结果:" + i);
    5. return i;
    6. }, pool);
    7. System.out.println(future.get());

     返回结果:

     

    可以理解为多线程同步调用。get方法为阻塞式等待。

    完成时的回调方法

    1、whenComplete

    1. CompletableFuture future = CompletableFuture.supplyAsync(() -> {
    2. System.out.println("当前线程:" + Thread.currentThread().getId());
    3. int i = 10 / 2;
    4. System.out.println("运行结果:" + i);
    5. return i;
    6. }, pool).whenComplete((result,exception)->{
    7. System.out.println("继续上一个线程的执行结果,用同一个线程继续执行");
    8. System.out.println("result="+result);
    9. System.out.println("exception="+exception);
    10. }).exceptionally(excep->{
    11. return 10; //遭遇到异常的返回结果
    12. });
    13. System.out.println(future.get());
    14. System.out.println("main ... end");

     执行结果:

    如果,i=10/0的执行结果如下:

    2、exceptionally

    总结:

    使用whenComplete的回调方法,参数一:返回结果;参数二:异常。但是该方法无法修改返回结果。是执行当前任务的线程继续执行回调方法的任务。

    whenCompleteAsync:是执行把whenCompleteAsync这个任务继续提交给线程池来进行执行。

    方法不以Async结尾,意味着Action使用相同的线程执行,而Async可能会使用其他线程执行。(如果是使用相同的线程池,也可能会被同一个线程选中执行)

    使用exceptionally,如果遭遇到异常,可以修改返回结果的值。

    3、handle方法完成后的处理

    1. CompletableFuture future = CompletableFuture.supplyAsync(() -> {
    2. System.out.println("当前线程:" + Thread.currentThread().getId());
    3. int i = 10 / 0;
    4. System.out.println("运行结果:" + i);
    5. return i;
    6. }, pool).handle((result,exception)->{
    7. if(result!=null){
    8. return result;
    9. }
    10. if(exception!=null){
    11. return 0;
    12. }
    13. return 0;
    14. });

     执行结果:

     

    4、线程串行化方法

    thenRunAsync:

    不得到上一步的返回结果,直接异步执行任务。

    1. CompletableFuture future = CompletableFuture.supplyAsync(() -> {
    2. System.out.println("当前线程:" + Thread.currentThread().getId());
    3. int i = 10 / 0;
    4. System.out.println("运行结果:" + i);
    5. return i;
    6. }, pool).thenRunAsync(()->{
    7. System.out.println("哈哈");
    8. },pool);

     注意:此时,i=10/0 肯定是抛出异常了,但是咱们抛出了异常,所以程序中断;

     如果修改异常代码,i=10/2;

    如果使用了thenRun,则是用该线程继续执行任务。

     

    thenAcceptAsync:

     

     得到上一步的返回结果,但是新任务结果不返回。

     

    1. CompletableFuture.supplyAsync(() -> {
    2. System.out.println("当前线程:" + Thread.currentThread().getId());
    3. int i = 10 / 2;
    4. System.out.println("运行结果:" + i);
    5. return i;
    6. }, pool).thenAccept(res->{
    7. System.out.println("res="+res);
    8. });

     执行结果:

    thenApplyAsync:

     

    得到上一步的返回结果,并且返回新任务的结果。

    1. CompletableFuture future = CompletableFuture.supplyAsync(() -> {
    2. System.out.println("当前线程:" + Thread.currentThread().getId());
    3. int i = 10 / 2;
    4. System.out.println("运行结果:" + i);
    5. return i;
    6. }, pool).thenApplyAsync(res -> {
    7. System.out.println("res=" + res);
    8. return 8;
    9. }, pool);
    10. System.out.println("get===="+future.get());
    11. System.out.println("main ... end");

     

     执行结果:

     

    两个任务组合,都要完成

    两个任务都完成以后,触发一个事件

    thenCombine:

    组合两个future,获取两个future的返回结果,并返回当前任务的返回值;

    thenAcceptBoth:

    组合两个future,获取两个future的返回结果,然后处理任务,没有返回值;

    runAfterBoth:组合两个future,不需要获取future的返回结果,只需要两个future处理任务完成后,处理该任务。

    1. CompletableFuture future01 = CompletableFuture.supplyAsync(() -> {
    2. System.out.println("线程1的ID:" + Thread.currentThread().getId());
    3. int i = 10 / 2;
    4. System.out.println("线程1结束:返回结果为" + i);
    5. return i;
    6. }, pool);
    7. CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
    8. System.out.println("线程2的ID:" + Thread.currentThread().getId());
    9. return "线程2结束";
    10. }, pool);
    11. //Async加上就是异步,到最后执行;不加就是约等于同步
    12. future01.runAfterBothAsync(future02,()->{
    13. System.out.println("runAfterBoth:"+"不要线程1和线程2的返回结果,新开一个独立线程运行,不是在线程池中");
    14. });

     

    1. future01.thenAcceptBothAsync(future02, (res1, res2) -> {
    2. System.out.println("thenAcceptBothAsync:" + "会获取到线程1和线程2的返回结果,res1=" + res1 + ",res2=" + res2 + ",但是新任务不会返回!");
    3. }, pool);

     

     

     

    1. CompletableFuture future = future01.thenCombineAsync(future02, (res1, res2) -> {
    2. return res1+"----"+res2;
    3. }, pool);
    4. System.out.println(future.get().toString());
    5. System.out.println("main ... end");
    6.  执行结果:

       

      两个任务组合,一个完成

      1. 当两个任务中,任意一个future任务完成的时候,执行该任务。
      2. applyToEither:两个任务有一个任务执行完成,获取它的返回值,处理任务并有新的返回值。
      3. acceptEither:两个任务有一个任务执行完成,获取它的返回值,处理任务,没有返回值。
      4. runAfterEither:两个任务有一个任务执行完成,不需要获取它的返回值,处理任务,并且没有返回值。

       

      多任务组合

      allOf:等待所有任务完成

      anyOf:只要有一个任务完成

      1. CompletableFuture<Void> allOf = CompletableFuture.allOf(future01, future02, future03);
      2. allOf.get();
      3. System.out.println("main ... end");

       

      执行结果:

      如果不加线程池,主线程结束,其余线程也会结束掉。其余线程就不打印东西了。所以要想清楚的看到结果,将线程执行放入到线程池中。  

       

       

       

    7. 相关阅读:
      四、ref与DOM-findDomNode-unmountComponentAtNode
      【雷达检测】基于复杂环境下的雷达目标检测技术(Matlab代码实现)
      【埋点探针】微信小程序SDK安装
      linux下的动态静态库
      uni-app 之 下拉刷新,上拉加载,获取网络列表数据
      图论-SPFA算法
      Docker篇-(2)-Docker安装-centos
      校园论坛(Java)—— 用户管理系统模块
      completablefuture使用案例代码
      生态保护促进经济效益-国稻种芯-万祥军:青海西宁现代农业
    8. 原文地址:https://blog.csdn.net/pshdhx/article/details/126322365
      • 最新文章
      • 攻防演习之三天拿下官网站群
        数据安全治理学习——前期安全规划和安全管理体系建设
        企业安全 | 企业内一次钓鱼演练准备过程
        内网渗透测试 | Kerberos协议及其部分攻击手法
        0day的产生 | 不懂代码的"代码审计"
        安装scrcpy-client模块av模块异常,环境问题解决方案
        leetcode hot100【LeetCode 279. 完全平方数】java实现
        OpenWrt下安装Mosquitto
        AnatoMask论文汇总
        【AI日记】24.11.01 LangChain、openai api和github copilot
      • 热门文章
      • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
        奉劝各位学弟学妹们,该打造你的技术影响力了!
        五年了,我在 CSDN 的两个一百万。
        Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
        面试官都震惊,你这网络基础可以啊!
        你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
        心情不好的时候,用 Python 画棵樱花树送给自己吧
        通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
        13 万字 C 语言从入门到精通保姆级教程2021 年版
        10行代码集2000张美女图,Python爬虫120例,再上征途
      Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
      正则表达式工具 cron表达式工具 密码生成工具

      京公网安备 11010502049817号