In Java ForkJoinTask, is fork / join order being executed?

Let's say we extended a RecursiveTask

called MyRecursiveTask

.

Then within forkJoinTask two subtasks are created:

MyRecursiveTask t1 = new MyRecursiveTask()
MyRecursiveTask t2 = new MyRecursiveTask()
t1.fork()
t2.fork()

      

I think then "t2" will be at the top of the desktop (which is the deque, it is used as the stack for the worker itself) as I saw the fork method implemented like this:

public final ForkJoinTask<V> fork() {
    Thread t;
    if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
        ((ForkJoinWorkerThread)t).workQueue.push(this);
    else
        ForkJoinPool.common.externalPush(this);
    return this;
}

      

if so, is there any performance difference for the two expressions below:

Expression1:

t1.join() + t2.join()

      

Expression2

t2.join() + t1.join()

      

I think it might make a difference. t1.join()

will always block (unless work is stolen) until completion t2.join()

, because only the task at the top of the workQueue can be entered. (In other words, t2 must be inserted before t1 is entered). Below are the codes for doJoin

and tryUnpush

.

private int doJoin() {
    int s; Thread t; ForkJoinWorkerThread wt; ForkJoinPool.WorkQueue w;
    return (s = status) < 0 ? s :
        ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
        (w = (wt = (ForkJoinWorkerThread)t).workQueue).
        tryUnpush(this) && (s = doExec()) < 0 ? s :
        wt.pool.awaitJoin(w, this, 0L) :
        externalAwaitDone();
}

/**
 * Pops the given task only if it is at the current top.
 * (A shared version is available only via FJP.tryExternalUnpush)
*/
final boolean tryUnpush(ForkJoinTask<?> t) {
    ForkJoinTask<?>[] a; int s;
    if ((a = array) != null && (s = top) != base &&
        U.compareAndSwapObject
        (a, (((a.length - 1) & --s) << ASHIFT) + ABASE, t, null)) {
        U.putOrderedInt(this, QTOP, s);
        return true;
    }
    return false;
}

      

Does anyone have any ideas about this? Thank!

+3


source to share


2 answers


Whether using Java7 or Java8 is important. In Java7, the environment creates continuation threads for join (). In Java8, the struct is usually closed for join (). See here. I've been writing criticism about this framework since 2010.

Recommendation for using recursive task (from JavaDoc):

return f2.compute() + f1.join();

      



Thus, the splitting thread continues with the operation itself.

Relying on the F / J code for direction is not recommended as this code changes frequently. For example, in Java8 using nested parallel threads, there were too many compensation threads that were reworked in Java8u40 to cause more problems. See here .

If you need to do multiple joins, then it really doesn't matter which order you join (). Each fork () makes a task available to any thread.

+5


source


If you have enough cores than both threads running in parallel, it doesn't matter which one starts first, because the completion time matters. So, depending on what ends up, the former must wait for the other to finish and calculate the result. If you have 1 core than what you think it may be true, but for 1 core why do you need to parallelize work?



0


source







All Articles