我将worktealingpool的大小设置为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
主要:主要
存根:ForkJoinPool-1-worker-3
接受:ForkJoinPool-1-worker-3
答案 0 :(得分:1)
Executors.newWorkStealingPool(1);
使用的ForkJoinPool
具有未记录的称为补偿线程的功能。
来自http://www.coopsoft.com/ar/CalamityArticle.html(重点是我):
JDK1.8引入了CompletableFuture类。引用JavaDoc:
“可以明确完成(设置其值和状态),并且可以包括在完成时触发的相关功能和动作的未来。”
JavaDoc中没有提到的是,当使用带有get()方法的大量依赖函数时,框架会创建“补偿线程” ,以继续从双端队列和提交队列中获取应用程序任务
因此,当您执行future.get();
时,它会阻塞,但是会创建另一个线程来执行任务。
运行代码时,我得到的输出是:
func:ForkJoinPool-1-worker-1
主要:主要
存根:ForkJoinPool-1- 工人-0
接受:ForkJoinPool-1-worker-1
您没有显示您的threadName()
方法,也许其中有一个错误,因此您看到的是相同的线程名称(或者在这种情况下,您使用了使用相同名称的不同JVM,请检查线程ID)?如果没有,请提供完整的代码,以将func和stub输出为相同的线程。
答案 1 :(得分:-1)
Future.get()块,这意味着Future.get()之后的代码在获得Result之前不会执行。即使在您的输出中,您也可以看到存根首先完成执行。您可以在返回语句之前尝试在存根中睡5分钟左右的时间,看看会发生什么吗?