Future.get 无法阻塞 forkjoinpool/workstealingpool 中的线程

Future.get cannot block the thread in forkjoinpool/workstealingpool

我把 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

Future.get() 和 stub 似乎使用了相同的 threead。

Future.get() 块,这意味着 Future.get() 之后的代码将在获得 Result 之前不会执行。即使在您的输出中,您也可以看到存根首先完成执行。您可以尝试在 return 语句之前在存根中休眠 5 分钟左右,看看会发生什么吗?

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 作为相同的线程输出。