ForkJoinPool源码解析(三)-- join
public final V join() { int s; if ((s = doJoin() & DONE_MASK) != NORMAL) reportException(s);//可能被取消或发生异常 return getRawResult(); } 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(); //是否已执行完 //是 直接返回任务状态 //否 当前线程是否是ForkJoinWorkerThread //是 执行workQueue的tryUnPush方法和doExec方法。这里的意思是移除在top的当前任务,然后自己主动执行 //移除成功 返回任务状态 //移除失败 调用awaitJoin方法 //否 执行externalAwaitDone } final int awaitJoin(WorkQueue w, ForkJoinTask<?> task, long deadline) { int s = 0; if (task != null && w != null) { //将当前任务变为队列的正在join的任务,先前的放到task的pervJoin,形成一个栈。 ForkJoinTask<?> prevJoin = w.currentJoin; U.putOrderedObject(w, QCURRENTJOIN, task); CountedCompleter<?> cc = (task instanceof CountedCompleter) ? (CountedCompleter<?>)task : null; for (;;) { //小于0说明完成 if ((s = task.status) < 0) break; //CountedCompleter任务由helpComplete来完成join if (cc != null) helpComplete(w, cc, 0); //如果队列为空或 执行任务没有成功则会去帮助偷窃. //执行失败说明任务被偷了。 //tryRemoveAndExec任务执行成功则会返回false //在当前队列任务执行完了或者 // 或者(在队列中没有找到这个任务且任务没有执行) //则这个任务是被偷了,偷窃任务的可能是在join。 //所以去帮助偷窃者执行他的任务。 else if (w.base == w.top || w.tryRemoveAndExec(task)) helpStealer(w, task); //如果任务执行成功则会跳出循环 if ((s = task.status) < 0) break; long ms, ns; if (deadline == 0L) ms = 0L; else if ((ns = deadline - System.nanoTime()) <= 0L) break; else if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) <= 0L) ms = 1L; //尝试补偿,在里面有进行 if (tryCompensate(w)) { //等待 task.internalWait(ms); //活跃线程加1 U.getAndAddLong(this, CTL, AC_UNIT); } } //还原当前队列正在join的任务 U.putOrderedObject(w, QCURRENTJOIN, prevJoin); } //返回任务的状态 return s; }
join这个方法我跟代码了,但是还是,唯一还算理解的就是join的task会形成一个栈。每个task都会执行fork,每次fork都会往自己的workqueue的task数组把自己方法进去。
然后在执行join的时候又会把自己弹出来 tryUnpush(this) 。依次执行并形成join栈。这样当任务拆解到足够小的时候,执行join就会返回了,这样它之前的任务也会返回了。