码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • Java组合异步编程(1)


    您好,我是湘王,这是我的CSDN博客,欢迎您来,欢迎您再来~

    在《计算机干活的两种方式》中我们提到过同步和异步的区别。所谓同步就是事情只能一件接一件地顺着干,而不能跳过。比如外卖小哥送外卖只能一件一件地送,不能说一件先送一半再送另一件。而异步就可以不按顺序出牌,但是这种不按顺序需要以互不影响为前提。比如李雷问韩梅梅一个数学问题,但是韩梅梅一时答不出来,李雷就先去干其他的事情去了。等韩梅梅知道答案的时候,再给李雷打电话告诉他结果。就像这样子:

     

    Java也支持这种异步工作模式。还是以代码来举例。

    1. public static void doSomethingElse() {
    2. try {
    3. System.out.println("doSomethingElse...");
    4. Thread.sleep(1_000);
    5. } catch (InterruptedException e) {
    6. e.printStackTrace();
    7. }
    8. }
    9. public static void executeComputation() {
    10. try {
    11. System.out.println("executeComputation...");
    12. Thread.sleep(2_000);
    13. } catch (InterruptedException e) {
    14. e.printStackTrace();
    15. }
    16. }
    17. // 使用Future
    18. public static void testExecutor() throws InterruptedException, ExecutionException {
    19. // 申请线程池执行
    20. ExecutorService es = Executors.newSingleThreadExecutor();
    21. Future f = es.submit(() -> {
    22. System.out.println(Thread.currentThread().getName());
    23. // 执行线程操作
    24. executeComputation();
    25. return 9527;
    26. });
    27. // 其他耗时操作
    28. doSomethingElse();
    29. System.out.println(f.get());
    30. es.shutdown();
    31. }

    运行代码后,也可以看到异步的执行痕迹。这可以用流程图来表示:

     

    代码中的Futrure,就是那个可以通知李雷的「电话」。

    那么问题来了,如果李雷有好几个不懂的问题,分别问了韩梅梅、赵梅梅、魏梅梅,而且需要答案之间有先后顺序怎么办呢?(比如要先得到韩梅梅的答案,再拿到赵梅梅的答案才有用)也就是对这种有多个「异步」任务的情况,该如何处理?这就是Java8中CompletableFuture(组合异步编程)要解决的问题。还是用代码来说话。

    假如现在有三个异步任务,要求这三个异步任务能够「按顺序」执行,可以试着这么写:

    1. ExecutorService service = Executors.newFixedThreadPool(3);
    2. System.out.println("main start ...");
    3. Future f1 = service.submit(() -> {
    4. System.out.println(Thread.currentThread().getName());
    5. // 执行线程操作
    6. executeComputation();
    7. return 9525;
    8. });
    9. Future f2 = service.submit(() -> {
    10. System.out.println(Thread.currentThread().getName());
    11. // 执行线程操作
    12. executeComputation();
    13. return 9526;
    14. });
    15. Future f3 = service.submit(() -> {
    16. System.out.println(Thread.currentThread().getName());
    17. // 执行线程操作
    18. executeComputation();
    19. return 9527;
    20. });
    21. System.out.println("main end ...");
    22. service.shutdown();

    但是运行之后发现,无论如何,「System.out.println("main end ...");」这行代码都不会最后执行,这就达不到「按顺序」执行的要求了。

    现在换成CompletableFuture试试看:

    1. ExecutorService service = Executors.newFixedThreadPool(3);
    2. System.out.println("main start ...");
    3. CompletableFuture future1 = CompletableFuture.supplyAsync(() -> {
    4. System.out.println("9525...");
    5. return 9525;
    6. }, service);
    7. CompletableFuture future2 = CompletableFuture.supplyAsync(() -> {
    8. System.out.println("9526...");
    9. return 9526;
    10. }, service);
    11. CompletableFuture future3 = CompletableFuture.supplyAsync(() -> {
    12. System.out.println("9527...");
    13. return 9527;
    14. }, service);
    15. CompletableFuture future = CompletableFuture.allOf(future1, future2, future3);
    16. future.get();
    17. System.out.println("main end ...");
    18. service.shutdown();

    运行后会发现9525、9526、9527三个任务虽然都是异步任务,但能够「按顺序」排列,满足了最初的要求。

    现在,更进一步,如果某个答案取决于两个不相干的问题的共同回答,该怎么实现呢?例如,李雷问韩梅梅,然后又问了赵梅梅,只有在都问她们两个人的情况下,她们才会说出答案,否则不给答案。

    1. // 两个CompletableFuture,全部任务执行完成才返回
    2. public static void testAllOf() throws InterruptedException, ExecutionException {
    3. CompletableFuture future1 = CompletableFuture.supplyAsync(() -> "Hello");
    4. CompletableFuture future2 = CompletableFuture.supplyAsync(() -> "world");
    5. CompletableFuture combinedFuture = CompletableFuture.allOf(future1, future2);
    6. // 返回值是void,不会合并结果
    7. System.out.println(combinedFuture.get());
    8. // 需要手动处理每个并行异步任务的结果
    9. String combined = Stream.of(future1, future2)
    10. .map(CompletableFuture::join)
    11. .collect(Collectors.joining(" "));
    12. // hello world
    13. System.out.println(combined);
    14. }

    这就是神奇的CompletableFuture组合异步编程。可以通过代码让不同的问题强制「同频」,这算不算乱点鸳鸯谱?

    当然,如果有同学觉得这很过分,也可以允许「只要有问了她们其中之一就立刻给答案」:

    1. // 两个CompletableFuture,只要有一个任务执行完成就返回
    2. public static void testAnyOf() throws InterruptedException, ExecutionException {
    3. CompletableFuture future1 = CompletableFuture.supplyAsync(() -> "Hello");
    4. CompletableFuture future2 = CompletableFuture.supplyAsync(() -> {
    5. try {
    6. Thread.sleep(2000);
    7. } catch (Exception e) {
    8. e.printStackTrace();
    9. }
    10. return "world";
    11. });
    12. CompletableFuture combinedFuture = CompletableFuture.anyOf(future1, future2);
    13. // Hello World
    14. System.out.println(combinedFuture.get());
    15. }
    16. 这更像唐伯虎点秋香中最后揭盖头的场景——只要揭了一个,剩下的全部自己揭开。


      感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~

    17. 相关阅读:
      2022蓝队HW初级面试题总结
      HTML网上书店静态HTML网页作业作品 大学生三联书店网页设计制作成品 简单DIV CSS布局网站
      如何在Java中轻松使用工厂设计模式
      基于 LLM 的知识图谱另类实践
      易点易动固定资产管理系统:精准管理与科学采购,降本增效的利器
      【网站架构】cpu、内存、带宽是否足够?负载分析,linux内核调优】
      Linux硬盘垃圾清理心得
      解决库存超卖问题
      JAVA错误 找不到或无法加载主类
      【Canvas】JavaScript用Canvas制作美丽的对称图案
    18. 原文地址:https://blog.csdn.net/lostrex/article/details/127777267
      • 最新文章
      • C# 内存安全性的重大演进:重新定义 unsafe 关键字
        [MAF的Agent管道详解-05]对话历史的持久化和输入输出的增强
        一行代码干翻 Java 反射?EggG 流式反射调用让反射优雅到不可思议
        云原生 CI/CD 平台架构设计
        模板方法模式实战:重构Agent工具审批,告别重复代码
        [MAF的Agent管道详解-03]连接LLM的IChatClient对象
        《HelloGitHub》第 122 期
        AI Agent 到底是做什么的?优势在哪里?
        完整学习LLM(六):上下文窗口是什么,为什么模型会忘东西
        和AI一起搞事情#6. 如何实现AI生图文字可编辑?
      • 热门文章
      • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
        奉劝各位学弟学妹们,该打造你的技术影响力了!
        五年了,我在 CSDN 的两个一百万。
        Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
        面试官都震惊,你这网络基础可以啊!
        你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
        心情不好的时候,用 Python 画棵樱花树送给自己吧
        通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
        13 万字 C 语言从入门到精通保姆级教程2021 年版
        10行代码集2000张美女图,Python爬虫120例,再上征途
      小工具 小游戏
      Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1

      京公网安备 11010502049817号