V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
7911364440
V2EX  ›  Java

关于 CompletableFuture 类的疑惑

  •  
  •   7911364440 · Aug 4, 2022 · 2765 views
    This topic created in 1363 days ago, the information mentioned may be changed or developed.
    CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 1)
                    .thenApplyAsync(i -> i+1)
                    .thenApplyAsync(i -> i+1)
                    .thenAccept(i -> System.out.println(i));
    

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

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

    至于异步的含义, 有可能是 D 依赖 C1, C2 的完成才能执行, 而 C1, C2 是可以并行跑的, C1 依赖 B, C2 依赖 A. 如果不用它提供的这个工具, 你自己要写这么一串, 代码会很长
    7911364440
        5
    7911364440  
    OP
       Aug 4, 2022
    @dqzcwxb 我的疑惑就是 thenApplyAsync 虽然会使用新的线程去执行任务,但也还是要等待前一个任务的返回值,使用新的线程去执行任务的意义是什么呢?
    JsonNode
        6
    JsonNode  
       Aug 4, 2022
    一个会阻塞主线程,一个不会?
    jiulang
        7
    jiulang  
       Aug 4, 2022
    未必是新的线程,是从池里取出一个当前空闲的线程来执行,执行完就放到池里
    yazinnnn
        8
    yazinnnn  
       Aug 4, 2022
    @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  
       Aug 4, 2022 via iPhone
    不同场景使用不同的线程池是很有必要的,默认的线程池并不适用所有的场景
    wangyu17455
        10
    wangyu17455  
       Aug 4, 2022   ❤️ 2
    不阻塞 io 线程就是意义,springboot 默认只给 tomcat200 条 io 线程,如果你的业务代码是异步的,返回了 CompletableFuture 或者 spring 的 Flux/Mono ,那就可以交给 netty 去调度你的代码,线程数量就不再会限制你的连接数,可以完全跑满 cpu 的性能而不会浪费大量的时间在线程切换上
    shyling
        11
    shyling  
       Aug 4, 2022
    一个是跑异步,一个是跑同步
    nekoneko
        12
    nekoneko  
       Aug 4, 2022
    10 楼说的对
    golangLover
        13
    golangLover  
       Aug 9, 2022 via Android
    看了上面的解释,说实话我觉得其他人并不在回答楼主的问题。看看用户 1283822 的回答


    https://stackoverflow.com/questions/47489338/what-is-the-difference-between-thenapply-and-thenapplyasync-of-java-completablef
    Aresxue
        14
    Aresxue  
       Aug 11, 2022
    因为大多数业务应用都是 io 密集型,这样可以更方便的压榨 cpu ,这么做的有 tomcat 、dubbo 、spring 、netty 等,接收请求的线程和处理线程一般都是分开的,业务代码这么做要看情况而定。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2675 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 53ms · UTC 15:57 · PVG 23:57 · LAX 08:57 · JFK 11:57
    ♥ Do have faith in what you're doing.