Java ForkJoinPool - order of tasks in queues Java ForkJoinPool - order of tasks in queues multithreading multithreading

Java ForkJoinPool - order of tasks in queues


  1. Your guess is correct, you are totally right.As you can read in the "Implementation overview".
 * Joining Tasks * ============= * * Any of several actions may be taken when one worker is waiting * to join a task stolen (or always held) by another.  Because we * are multiplexing many tasks on to a pool of workers, we can't * just let them block (as in Thread.join).  We also cannot just * reassign the joiner's run-time stack with another and replace * it later, which would be a form of "continuation", that even if * possible is not necessarily a good idea since we may need both * an unblocked task and its continuation to progress.  Instead we * combine two tactics: * *   Helping: Arranging for the joiner to execute some task that it *      would be running if the steal had not occurred. * *   Compensating: Unless there are already enough live threads, *      method tryCompensate() may create or re-activate a spare *      thread to compensate for blocked joiners until they unblock.

2.Both ForkJoinPool.invoke and ForkJoinPool.join are the exactly the same in the manner the task is submitted. You can see in the code

    public <T> T invoke(ForkJoinTask<T> task) {        if (task == null)            throw new NullPointerException();        externalPush(task);        return task.join();    }    public void execute(ForkJoinTask<?> task) {        if (task == null)            throw new NullPointerException();        externalPush(task);    }

In the externalPush you can see that the task is added to a randomly-selected worker queue using ThreadLocalRandom. Moreover, it entered to the head of the queue using a push method.

    final void externalPush(ForkJoinTask<?> task) {        WorkQueue[] ws; WorkQueue q; int m;        int r = ThreadLocalRandom.getProbe();        int rs = runState;        if ((ws = workQueues) != null && (m = (ws.length - 1)) >= 0 &&            (q = ws[m & r & SQMASK]) != null && r != 0 && rs > 0 &&            U.compareAndSwapInt(q, QLOCK, 0, 1)) {            ForkJoinTask<?>[] a; int am, n, s;            if ((a = q.array) != null &&                (am = a.length - 1) > (n = (s = q.top) - q.base)) {                    int j = ((am & s) << ASHIFT) + ABASE;                U.putOrderedObject(a, j, task);                U.putOrderedInt(q, QTOP, s + 1);                U.putIntVolatile(q, QLOCK, 0);                if (n <= 1)                    signalWork(ws, q);                return;            }            U.compareAndSwapInt(q, QLOCK, 1, 0);        }        externalSubmit(task);    }

I am not sure what do you mean by that:

And does this depend on whether the thread calling pool.execute(task) or pool.invoke(task) is an external thread or a thread within this fork-join pool?