我把workstealingpool的大小设置为1,看来future.get()并没有阻塞线程。
@Test
public void runAsyncThenApplyExample() {
ExecutorService executor = Executors.newWorkStealingPool(1);
CompletableFuture cf = CompletableFuture.supplyAsync(
() -> {
//assertTrue(Thread.currentThread().isDaemon());
System.out.println("func: " + threadName());
Callable<Long> callable = () ->stub();
Future<Long> future = executor.submit(callable);
try {
future.get(); <<<<< **I think this should block the thread**
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
return 1;
}, executor).thenAccept(s -> {
System.out.println("accept: " + threadName());
});
//assertFalse(cf.isDone());
System.out.println("main: " + threadName());
sleep(10);
assertTrue(cf.isDone());
}
private Long stub() {
System.out.println("stub: " + threadName());
return 1L;
}
private String threadName() {
return Thread.currentThread().getName();
}
输出:
func: ForkJoinPool-1-worker-3
main: main
stub: ForkJoinPool-1-worker-3
accept: ForkJoinPool-1-worker-3
最佳答案
Executors.newWorkStealingPool(1);
使用 ForkJoinPool
,它有一个未记录的功能,称为补偿线程。
来自 http://www.coopsoft.com/ar/CalamityArticle.html (强调我的):
Introduced with JDK1.8 is the CompletableFuture Class. To quote the JavaDoc:
“A Future that may be explicitly completed (setting its value and status), and may include dependent functions and actions that trigger upon its completion.”
Not mentioned in the JavaDoc is that when using a large number of dependent functions with a get() method, the framework creates “compensation threads” to continue fetching application tasks from the deques and submission queue.
因此,当您执行 future.get();
时,它会阻塞,但会创建另一个线程来执行任务。
当运行你的代码时,我得到的输出是:
func: ForkJoinPool-1-worker-1
main: main
stub: ForkJoinPool-1-worker-0
accept: ForkJoinPool-1-worker-1
您还没有显示您的 threadName()
方法,可能其中有错误,因此您看到了相同的线程名称(或者您使用了使用相同名称的不同 JVM在这种情况下,检查线程 ID)?如果没有,请提供将 func 和 stub 作为相同线程输出的完整代码。
关于java - Future.get 无法阻塞 forkjoinpool/workstealingpool 中的线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56233669/