【ForkJoin的运行原理简析】
1.CaLL ForkJoinPool.invoke(ForkJoinTask)
2.put the given task into taskqueue of the pool(addSubmission(task);)
3.the a ForkJoinWorkerThread will scan the queue,call ForkJoinTask.doExec(),then call
exec() method in concrete-ForkJoinTask like RecursiveTask
4.exec() method in RecursiveTask is like this:
Its an implementation of abstract method in ForkJoinTask;
protected final boolean exec() {
result = compute();
return true;
}
here the method compute() finally been invoked,the compute() should be implemented by user
【ForkJoinPool如何获得 ForkJoinWorkerThread】
See from the constructor of ForkJoinPool.
public ForkJoinPool() {
this(Runtime.getRuntime().availableProcessors(),
defaultForkJoinWorkerThreadFactory, null, false);
}
public ForkJoinPool(
int parallelism, /*可用的处理器个数,通过Runtime调用native的availableProcessors()获取*/
ForkJoinWorkerThreadFactory factory,
/*简单工厂模式,这里用了默认的工作线程工厂*/
Thread.UncaughtExceptionHandler handler,
/*工作线程异常终止(不可恢复)时的处理者,一般为null,不指定*/
boolean asyncMode)
/*<最后一个参数的说明>*/
@param asyncMode if true,
* establishes local first-in-first-out scheduling mode for forked
* tasks that are never joined. This mode may be more appropriate
* than default locally stack-based mode in applications in which
* worker threads only process event-style asynchronous tasks.
* For default value, use {@code false}.
默认是false,使用默认的,基于栈的对fork task调度方式,即最新fork出来的任务,在栈顶,执行完后出栈,将result返回给栈的上一级fork tasks。 如果为true,则使用先进先出的调度方式,在工作线程只处理异步的,事件形式的任务时,用这种方式更合适(像消息队列,事件队列一样处理)。
/*构造函数解析*/
{
checkPermission();
if (factory == null)
throw new NullPointerException();
if (parallelism <= 0 || parallelism > MAX_ID)
throw new IllegalArgumentException();
this.parallelism = parallelism;
this.factory = factory;
this.ueh = handler;
this.locallyFifo = asyncMode;
long np = (long)(-parallelism); // offset ctl counts
this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
this.submissionQueue = new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY]; /*创建一个 ForkJoinTask 数组作为任务队列,默认8*/
// initialize workers array with room for 2*parallelism if possible /*为什么工作线程数,要是处理器个数的2倍?*/
int n = parallelism << 1;
if (n >= MAX_ID)
n = MAX_ID;
else { // See Hackers Delight, sec 3.2, where n < (1 << 16)
/*Hackers Delight,一本基于计算机体系结构讲解算法实现的书*/
n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8;
/*逻辑右移,左边补0,算术右移补符号位,右边均截掉*/
}
workers = new ForkJoinWorkerThread[n + 1];
/*工作线程数组*/
this.submissionLock = new ReentrantLock();
/*任务队列的锁,并且是条件锁,用于添加任务时进行同步*/
this.termination = submissionLock.newCondition();
StringBuilder sb = new StringBuilder("ForkJoinPool-");
sb.append(poolNumberGenerator.incrementAndGet());
sb.append("-worker-");
this.workerNamePrefix = sb.toString();
}
/*ForkJoinWorkerThread 数组,如何与ForkJoinTask关联?*/
ForkJoinPool的invoke方法,调用 addSubmission 方法
【将待执行的任务,加入到任务队列】
private void addSubmission(ForkJoinTask<?> t)
{
final ReentrantLock lock = this.submissionLock; /*get lock created in constructor*/
lock.lock();
try {
ForkJoinTask<?>[] q;
int s, m;
if ((q = submissionQueue) != null)
/*check if task queue is not null*/
{ // ignore if queue removed
long u = (((s = queueTop) & (m = q.length-1)) << ASHIFT)+ABASE; /*不知道计算什么*/
UNSAFE.putOrderedObject(q, u, t);
/*使用了 sun.misc.Unsafe库的接口,将指定的task添加到任务队列 submissionQueue(存储值到指定字段,但不提供可见性,如果需要具备可见性,则需要指定字段为volatile)*/
queueTop = s + 1;
if (s - queueBase == m)
/*如果任务队列 submissionQueue 满了,则扩容*/
growSubmissionQueue();
}
} finally {
lock.unlock();
}
signalWork();
/*Wakes up or creates a worker*/
}
【创建worker-thread,执行任务队列的任务】
final void signalWork() {
...
addWorker();
}
private void addWorker()
{
Throwable ex = null;
ForkJoinWorkerThread t = null;
try {
t = factory.newThread(this);
/*创建一个thread对象*/
} catch (Throwable e) {
ex = e;
}
if (t == null) { // null or exceptional factory return
long c; // adjust counts
do {} while (!UNSAFE.compareAndSwapLong
(this, ctlOffset, c = ctl,
(((c - AC_UNIT) & AC_MASK) |
((c - TC_UNIT) & TC_MASK) |
(c & ~(AC_MASK|TC_MASK)))));
// Propagate exception if originating from an external caller
if (!tryTerminate(false) && ex != null &&
!(Thread.currentThread() instanceof ForkJoinWorkerThread))
UNSAFE.throwException(ex);
}
else
t.start();
/*启动线程*/
}
【ForkJoinWorkerThread 的执行函数】
public void run()
{
Throwable exception = null;
try {
onStart();
pool.work(this);
/*执行 ForkJoinPool 对象的work方法,ForkJoinPool对象在创建worker-thread的时候指定,pool使用当前线程扫描任务队列*/
} catch (Throwable ex) {
exception = ex;
} finally {
onTermination(exception);
}
}
【worker-thread怎么执行到 submissionQueue 里的task? 】
final void work(ForkJoinWorkerThread w)
{
boolean swept = false; // true on empty scans
long c;
while (!w.terminate && (int)(c = ctl) >= 0) {
/*检查worker-thread是否终结,*/
int a; // active count
if (!swept && (a = (int)(c >> AC_SHIFT)) <= 0)
swept = scan(w, a);
/*在scan方法中,调用 ForkJoinWorkerThread.execTask(ForkJoinTask),execTask方法将调用 ForkJoinTask.doExec(),进而
调用用户实现的 compute() 方法,将结果保存在Task的result中*/
else if (tryAwaitWork(w, c))
swept = false;
}
}
【新增的worker-thread,怎样加入到ForkJoinPool的workers数组?】
/*在worker-thread的构造函数中,调用pool的 registerWorker 方法*/
protected ForkJoinWorkerThread(ForkJoinPool pool)
{
super(pool.nextWorkerName());
this.pool = pool;
int k = pool.registerWorker(this);
...
}
【invoke如何等待compute执行完后,返回result】
ForkJoinPool的invoke方法中,最后调用 task.join()方法,等待task线程执行完毕,然后返回结果
【真实的例子】