Future.get cannot block the thread in forkjoinpool/workstealingpool

zero :

I set the size of workstealingpool as 1. It seems that the future.get() doesn't block the thread.

@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();
}

output:

func: ForkJoinPool-1-worker-3
main: main
stub: ForkJoinPool-1-worker-3
accept: ForkJoinPool-1-worker-3

It seems that Future.get() and stub are using the same threead. enter image description here

enter image description here

Oleg :

Executors.newWorkStealingPool(1); uses ForkJoinPool which has an undocumented feature called compensation threads.

From http://www.coopsoft.com/ar/CalamityArticle.html (emphasis mine):

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.

So when you do future.get(); it blocks but another thread is created in which the task is executed.

When running your code the output I'm getting is:

func: ForkJoinPool-1-worker-1
main: main
stub: ForkJoinPool-1-worker-0
accept: ForkJoinPool-1-worker-1

You haven't showed your threadName() method maybe there is a mistake in it and because of that you're seeing the same thread name (or you use different JVM which uses the same name in such case, check the thread ID)? If not please provide full code which outputs func and stub as the same threads.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=105349&siteId=1