bigywater.tech
Java · 291

CompletableFuture 默认执行器

thenApply 到底在哪个线程跑?传了自定义线程池,后面的 thenApplyAsync 还会用它吗?commonPool 太小时会怎样?这篇逐个打印线程名。

9 → 1
commonPool 并行度改为 1 后,默认执行器从 ForkJoinPool 变成 ThreadPerTaskExecutor
不沿用
thenApplyAsync 不传执行器时不会沿用 supplyAsync 用的自定义池
没有中断
cancel(true) 与 orTimeout 都没有打断正在 sleep 的任务

执行线程

实测 · 本机执行输出
    main 线程名 = main;commonPool 并行度 = 9
    1 已完成的 future.thenApply:在 main
    2 已完成的 future.thenApplyAsync:在 ForkJoinPool.commonPool-worker-1
    3 已完成的 future.thenApplyAsync(…, mine):在 mine
    4 supplyAsync 睡 200 ms 后 thenApply(挂在未完成的上面):供给在 ForkJoinPool.commonPool-worker-1,thenApply 在 ForkJoinPool.commonPool-worker-1
    5 supplyAsync(…, mine) 后 thenApply:供给在 mine,thenApply 在 mine
    6 supplyAsync(…, mine) 后 thenApplyAsync(不传执行器):供给在 mine,thenApplyAsync 在 ForkJoinPool.commonPool-worker-1
    7 手动 complete(在线程 main2 里调用):完成者线程是 main2 → thenApply 在 main2
    8 已经完成,在 main 里再挂 thenApply → main
    9 defaultExecutor():ForkJoinPool

commonPool 并行度

实测 · 本机执行输出
  JVM 选项 默认:
      commonPool 并行度=9;CompletableFuture 默认执行器类型=ForkJoinPool
      两个 supplyAsync 的线程名:ForkJoinPool.commonPool-worker-1 daemon=true | ForkJoinPool.commonPool-worker-1 daemon=true
  JVM 选项 -Djava.util.concurrent.ForkJoinPool.common.parallelism=1:
      commonPool 并行度=1;CompletableFuture 默认执行器类型=CompletableFuture$ThreadPerTaskExecutor
      两个 supplyAsync 的线程名:Thread-0 daemon=false | Thread-1 daemon=false
  JVM 选项 -Djava.util.concurrent.ForkJoinPool.common.parallelism=0:
      commonPool 并行度=1;CompletableFuture 默认执行器类型=CompletableFuture$ThreadPerTaskExecutor
      两个 supplyAsync 的线程名:Thread-0 daemon=false | Thread-1 daemon=false

超时与取消

实测 · 本机执行输出
      main 返回之前不等待;commonPool 线程是守护线程:true
      orTimeout:ExecutionException cause=java.util.concurrent.TimeoutException
      completeOnTimeout:默认值
      [ForkJoinPool.commonPool-worker-1] 任务结束
      超时回调所在线程 = CompletableFutureDelayScheduler
      慢任务被 orTimeout 之后 isCompletedExceptionally=true
      cancel(true) 的效果:true
      被 cancel(true) 的任务睡满了 500 ms,没有收到中断
      慢任务的 sleep 自己结束了(没有被 orTimeout 打断)
      main 结束

分步演示

CompletableFuture 与执行器
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12,Apple Silicon(commonPool 并行度 9)
    • 没有验证:Thread.ofVirtual 等虚拟线程执行器作为参数、更长链路中的 StackOverflow 保护、get 与 join 的异常包装差异的完整表、JDK 其它版本
    京ICP备2026067502号-1京公网安备11010502063487号