Future.get无法在forkjoinpool / workstealingpool中阻止线程

时间:2019-05-21 07:54:49

标签: java concurrency block future forkjoinpool

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

似乎Future.get()和stub使用相同的Threead。 enter image description here

enter image description here

2 个答案:

答案 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分钟左右的时间,看看会发生什么吗?