我想要实现的目标:
我想创建一个在 ExecutorService 上运行的 CompletableFuture,然后向其中添加一个在不同 ExecutorService 中执行的阶段。
我尝试过的:
try (ExecutorService benchRunner = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() - 1);
ExecutorService resultHandler = Executors.newVirtualThreadPerTaskExecutor()) {
for (Algorithm algorithm : Algorithm.values()) {
for (Distribution distribution : Distribution.values()) {
for (Integer arraySize : List.of(30, 60, 90, 300, 600, 900, 3000, 6000, 9000)) {
SortingBenchmark.Config config = new SortingBenchmark.Config(arraySize, algorithm, distribution);
CompletableFuture<Benchmark> benchmarkTask = new CompletableFuture<>();
benchmarkTask.completeAsync(new SortingBenchmark(config), benchRunner);
benchmarkTask.whenCompleteAsync((b, t) -> {
if (t != null) {
System.err.println("Failed on: " + config);
return;
}
System.out.println("Finished: " + config);
}, resultHandler);
}
}
}
}
我的理解是,
whenCompleteAsync
应该在resultHandler
在new SortingBenchmark(config)
上执行之后在benchRunner
上执行。但是,当我运行它时,whenCompleteAsync
部分中的代码永远不会运行;然而 completeAsync
部分运行得很好(我可以看出,因为我的 7 个核心固定为 100% 使用率,并且我看到了标准输出)。
如果我向
join
添加 benchmarkTask
调用,whenCompleteAsync
中的代码开始运行,但这个“解决方案”最终(自然地)导致整个部分变成单线程。
我是否误解了
whenCompleteAsync
的工作原理?我该如何实现我想要的目标?
谢谢,
归功于slaw,
问题在于 try-with-resources 语句强制对资源调用
close
的顺序进行反向排序;即,最后启动的资源首先被 close
d。
在上面的示例中,这会导致
resultHandler
在提交给 close
的任务完成之前被 benchRunner
处理。
颠倒资源初始化的顺序可以解决该问题。