ForkJoinPool invoke、execute和submit区别

使用ForkJoinPool的时候发现执行任务的方法有:

  • invoke(ForkJoinTask task)
  • execute(ForkJoinTask task)
  • submit(ForkJoinTask task)

三种方式,现在总结下区别。
首先比较execute和submit的区别,观察源码发现:

    /**
     * Arranges for (asynchronous) execution of the given task.
     *
     * @param task the task
     * @throws NullPointerException if the task is null
     * @throws RejectedExecutionException if the task cannot be
     *         scheduled for execution
     */
    public void execute(ForkJoinTask task) {
        if (task == null)
            throw new NullPointerException();
        externalPush(task);
    }
    /**
     * Submits a ForkJoinTask for execution.
     *
     * @param task the task to submit
     * @param  the type of the task's result
     * @return the task
     * @throws NullPointerException if the task is null
     * @throws RejectedExecutionException if the task cannot be
     *         scheduled for execution
     */
    public  ForkJoinTask submit(ForkJoinTask task) {
        if (task == null)
            throw new NullPointerException();
        externalPush(task);
        return task;
    }

从方法体和返回参数可以看出,两者逻辑大致相同,都是首先对任务做非空校验,再将任务压入执行队列,唯一的不同是submit会把任务对象本身返回,返回后我们可以通过get()获取方法执行结果。

再看invoke()

    /**
     * Performs the given task, returning its result upon completion.
     * If the computation encounters an unchecked Exception or Error,
     * it is rethrown as the outcome of this invocation.  Rethrown
     * exceptions behave in the same way as regular exceptions, but,
     * when possible, contain stack traces (as displayed for example
     * using {@code ex.printStackTrace()}) of both the current thread
     * as well as the thread actually encountering the exception;
     * minimally only the latter.
     *
     * @param task the task
     * @param  the type of the task's result
     * @return the task's result
     * @throws NullPointerException if the task is null
     * @throws RejectedExecutionException if the task cannot be
     *         scheduled for execution
     */
    public  T invoke(ForkJoinTask task) {
        if (task == null)
            throw new NullPointerException();
        externalPush(task);
        return task.join();
    }

submit()不同的是返回task.join(),再看join()方法

    /**
     * Returns the result of the computation when it {@link #isDone is
     * done}.  This method differs from {@link #get()} in that
     * abnormal completion results in {@code RuntimeException} or
     * {@code Error}, not {@code ExecutionException}, and that
     * interrupts of the calling thread do not cause the
     * method to abruptly return by throwing {@code
     * InterruptedException}.
     *
     * @return the computed result
     */
    public final V join() {
        int s;
        if ((s = doJoin() & DONE_MASK) != NORMAL)
            reportException(s);
        return getRawResult();
    }

首先判断任务是否执行完毕,若未执行完毕,抛出任务取消或者任务异常的异常Exception,否则获取任务执行结果。而getRawResult()就是取任务的结果返回。这里看判断任务执行完毕的doJoin()方法

    /**
     * Implementation for join, get, quietlyJoin. Directly handles
     * only cases of already-completed, external wait, and
     * unfork+exec.  Others are relayed to ForkJoinPool.awaitJoin.
     *
     * @return status upon completion
     */
    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();
    }

这里用了多个三元运算符,整理下逻辑

  • 判断当前任务的执行状态
    • 当前状态不是已完成
      • 当前线程是ForkJoin线程
        • 从工作队列中取出一个任务执行
      • 否则等待当前任务执行完毕

所以invoke()方法的调用,会一直阻塞到任务执行完成返回

总结一下:

  1. execute(ForkJoinTask) 异步执行tasks,无返回值
  2. invoke(ForkJoinTask) 有Join, tasks会被同步到主进程
  3. submit(ForkJoinTask) 异步执行,且带Task返回值,可通过task.get 实现同步到主线程

你可能感兴趣的:(Java)