ForkJoinFramwork, call compute() directly without explicit ForkJoinPool/ExecutorService

Tags: , ,



Q: What happens when the compute() method, in a class “X” that extends RecursiveAction/Task, is directly called?

Without calling a ForkJoinPool explicitly like the following:

ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<?> task = new X(...);
pool.invoke(task);

Instead a function call like the following still produce a similar result:

// X extends RecursiveAction/Task<V>, which also means it is a subclass of ForkJoinTask.
X x = new X(...);
x.compute();

What happens when the fork()/invokeAll() method inside class X is called (explicit ExecutorService is absent)?

My assumption would be, when an fork() or invoke() method inside the extended class X is called, a new task is automatically submitted to the ForkJoinPool.commonPool(), if no pool is explicitly specified. But I couldn’t find any document that specifies this behavior.

(Citation from the oracle documentation that might be relative)

A “main” ForkJoinTask begins execution when it is explicitly submitted to a ForkJoinPool, or, if not already engaged in a ForkJoin computation, commenced in the ForkJoinPool.commonPool() via fork(), invoke(), or related methods.

Any info or keywords would be appreciated.

A code snippet (note the “othertask.fork()”):

class X extends RecursiveTask<Double>{
    private Double[] numbersToBeOperated;
    private int start;
    private int end;
    
    public X(Double numbersToBeOperated, int start, int end){
        // define the fields, i.e., this.* = *;
    }
    @Override
    protected Double compute(){
        if(taskDividedToBaseCase){
            // do works
        } else {
            int middle = start + ((end - start) / 2);
            RecursiveTask<Double> otherTask = new X(numbersToBeOperated, start, middle);
            otherTask.fork(); // what happens here, when compute() is directly called?
            return new X(numbersToBeOperated, middle, end).compute() + otherTask.join();
            // or invokeAll(new X(...), new X(...)); if RecursiveAction
        }
    }
}
// then instantiate X and call X.compute() directly. 

Answer

Citing java.util.concurrent.ForkJoinTask<V>.fork():

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().

It do goes to the commonPool().

Also thanks @Holger for pointing to this documentation.



Source: stackoverflow