ForkJoinPool invoke、execute和subm
2021-08-24 本文已影响0人
IOXusu
使用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()方法的调用,会一直阻塞到任务执行完成返回
总结一下:
execute(ForkJoinTask) 异步执行tasks,无返回值
invoke(ForkJoinTask) 有Join, tasks会被同步到主进程
submit(ForkJoinTask) 异步执行,且带Task返回值,可通过task.get 实现同步到主线程