How does ForkJoinPool#awaitQuiescence actually work?

zexed640

I have next implementation of RecursiveAction, single purpose of this class - is to print from 0 to 9, but from different threads, if possible:

public class MyRecursiveAction extends RecursiveAction {
    private final int num;

    public MyRecursiveAction(int num) {
        this.num = num;
    }

    @Override
    protected void compute() {
        if (num < 10) {
            System.out.println(num);
            new MyRecursiveAction(num + 1).fork();
        }
    }
}

And I thought that invoking awaitQuiescence will make current thread to wait until all tasks (submitted and forked) will be completed:

public class Main {
    public static void main(String[] args) {
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        forkJoinPool.execute(new MyRecursiveAction(0));
        System.out.println(forkJoinPool.awaitQuiescence(5, TimeUnit.SECONDS) ? "tasks" : "time");
    }
}

But I don't always get correct result, instead of printing 10 times, prints from 0 to 10 times.

But if I add helpQuiesce to my implementation of RecursiveAction:

public class MyRecursiveAction extends RecursiveAction {
    private final int num;

    public MyRecursiveAction(int num) {
        this.num = num;
    }

    @Override
    protected void compute() {
        if (num < 10) {
            System.out.println(num);
            new MyRecursiveAction(num + 1).fork();
        }

        helpQuiesce();//here
    }
}

Everything works fine.

I want to know for what actually awaitQuiescence waiting?

Holger

You get an idea of what happens when you change the System.out.println(num); to System.out.println(num + " " + Thread.currentThread());

This may print something like:

0 Thread[ForkJoinPool-1-worker-3,5,main]
1 Thread[main,5,main]
tasks
2 Thread[ForkJoinPool.commonPool-worker-3,5,main]

When awaitQuiescence detects that there are pending tasks, it helps out by stealing one and executing it directly. Its documentation says:

If called by a ForkJoinTask operating in this pool, equivalent in effect to ForkJoinTask.helpQuiesce(). Otherwise, waits and/or attempts to assist performing tasks until this pool isQuiescent() or the indicated timeout elapses.

Emphasis added by me

This happens here, as we can see, a task prints “main” as its executing thread. Then, the behavior of fork() is specified as:

Arranges to asynchronously execute this task in the pool the current task is running in, if applicable, or using the ForkJoinPool.commonPool() if not inForkJoinPool().

Since the main thread is not a worker thread of a ForkJoinPool, the fork() will submit the new task to the commonPool(). From that point on, the fork() invoked from a common pool’s worker thread will submit the next task to the common pool too. But awaitQuiescence invoked on the custom pool doesn’t wait for the completion of the common pool’s tasks and the JVM terminates too early.

If you’re going to say that this is a flawed API design, I wouldn’t object.

The solution is not to use awaitQuiescence for anything but the common pool¹. Normally, a RecursiveAction that splits off sub tasks should wait for their completion. Then, you can wait for the root task’s completion to wait for the completion of all associated tasks.

The second half of this answer contains an example of such a RecursiveAction implementation.

¹ awaitQuiescence is useful when you don’t have hands on the actual futures, like with a parallel stream that submits to the common pool.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

How does -Infinity actually work?

분류에서Dev

How does COBOL actually accept numeric values?

분류에서Dev

Why and how does this work?

분류에서Dev

How does this work in javascript

분류에서Dev

endturnwithnextparticipants, how does it work?

분류에서Dev

How does SimpleCORSFilter work?

분류에서Dev

Phonegap how does it work?

분류에서Dev

How does collect static work?

분류에서Dev

How does "newElements" work in Javascript?

분류에서Dev

How does scanr work? Haskell

분류에서Dev

how does readyRead() work in Qt?

분류에서Dev

How does this pointer typecasting work?

분류에서Dev

How does shared hosting work?

분류에서Dev

How does ServiceNameQuery work in AngularJS

분류에서Dev

How does the INTERVAL datatype work?

분류에서Dev

How does file compression work?

분류에서Dev

How does Windows API work?

분류에서Dev

how does int*& variableName work ?

분류에서Dev

How does 'telnet localhost' work?

분류에서Dev

What does yum actually do?

분류에서Dev

What does yum actually do?

분류에서Dev

How does Linux differentiate between opening a file in read mode and actually reading data from it?

분류에서Dev

How does return work for a function local variable?

분류에서Dev

How does * to access pointers of variables or arrays work?

분류에서Dev

How does Xojo UI rendering for desktop work?

분류에서Dev

How does this implementation of array intersection work?

분류에서Dev

How does Gradient.Evaluate work internally?

분류에서Dev

How Does Initalizing a Javascript Modal Work in Materializecss?

분류에서Dev

How does Eclipse web service explorer work?