V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
7911364440
V2EX  ›  Java

关于 CompletableFuture 类的疑惑

  •  
  •   7911364440 · 2022-08-04 11:17:31 +08:00 · 2245 次点击
    这是一个创建于 849 天前的主题,其中的信息可能已经有所发展或是发生改变。
    CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 1)
                    .thenApplyAsync(i -> i+1)
                    .thenApplyAsync(i -> i+1)
                    .thenAccept(i -> System.out.println(i));
    

    thenApplyAsync()thenApply()这两个方法都需要等待前一个任务的返回值,那么thenApplyAsync()异步的含义是什么?

    14 条回复    2022-08-11 13:13:12 +08:00
    momocraft
        1
    momocraft  
       2022-08-04 11:21:03 +08:00
    thenApplyAsync 的参数函数会跑在不同的线程
    dqzcwxb
        2
    dqzcwxb  
       2022-08-04 11:23:43 +08:00
    所有带 Async 的方法都意味着会使用新的线程池去执行任务,如果你不指定则使用默认的 ForkJoinPool 线程池指定则使用你指定的线程池
    理论上也有可能会是同一个线程去执行,比如线程池就 1 个线程或者刚好调度到同一个线程
    Jooooooooo
        4
    Jooooooooo  
       2022-08-04 11:30:40 +08:00
    你试着不用这个功能把 A, B, C 三个任务串起来写, 会非常恶心. 它这个是极大简化前后有关联的任务写法.

    至于异步的含义, 有可能是 D 依赖 C1, C2 的完成才能执行, 而 C1, C2 是可以并行跑的, C1 依赖 B, C2 依赖 A. 如果不用它提供的这个工具, 你自己要写这么一串, 代码会很长
    7911364440
        5
    7911364440  
    OP
       2022-08-04 11:34:31 +08:00
    @dqzcwxb 我的疑惑就是 thenApplyAsync 虽然会使用新的线程去执行任务,但也还是要等待前一个任务的返回值,使用新的线程去执行任务的意义是什么呢?
    lovedoing
        6
    lovedoing  
       2022-08-04 11:43:20 +08:00
    一个会阻塞主线程,一个不会?
    jiulang
        7
    jiulang  
       2022-08-04 11:47:18 +08:00
    未必是新的线程,是从池里取出一个当前空闲的线程来执行,执行完就放到池里
    yazinnnn
        8
    yazinnnn  
       2022-08-04 12:29:58 +08:00
    @7911364440

    public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action);
    如果直接使用这个 api 的话, 貌似跟 thenAccept 没啥区别


    public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action,
    Executor executor)
    如果用这个的话, 可以将后续任务切换到其他线程池中进行, 比如之前运行在 eventloop 线程, 接下来的任务是阻塞耗时操作, 那么可以切换到 worker 线程中进行
    msaionyc
        9
    msaionyc  
       2022-08-04 12:39:58 +08:00 via iPhone
    不同场景使用不同的线程池是很有必要的,默认的线程池并不适用所有的场景
    wangyu17455
        10
    wangyu17455  
       2022-08-04 12:53:22 +08:00   ❤️ 2
    不阻塞 io 线程就是意义,springboot 默认只给 tomcat200 条 io 线程,如果你的业务代码是异步的,返回了 CompletableFuture 或者 spring 的 Flux/Mono ,那就可以交给 netty 去调度你的代码,线程数量就不再会限制你的连接数,可以完全跑满 cpu 的性能而不会浪费大量的时间在线程切换上
    shyling
        11
    shyling  
       2022-08-04 13:19:40 +08:00
    一个是跑异步,一个是跑同步
    nekoneko
        12
    nekoneko  
       2022-08-04 20:23:08 +08:00
    10 楼说的对
    golangLover
        13
    golangLover  
       2022-08-09 06:12:02 +08:00 via Android
    看了上面的解释,说实话我觉得其他人并不在回答楼主的问题。看看用户 1283822 的回答


    https://stackoverflow.com/questions/47489338/what-is-the-difference-between-thenapply-and-thenapplyasync-of-java-completablef
    Aresxue
        14
    Aresxue  
       2022-08-11 13:13:12 +08:00
    因为大多数业务应用都是 io 密集型,这样可以更方便的压榨 cpu ,这么做的有 tomcat 、dubbo 、spring 、netty 等,接收请求的线程和处理线程一般都是分开的,业务代码这么做要看情况而定。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2612 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 11:22 · PVG 19:22 · LAX 03:22 · JFK 06:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.