Fork/Join框架之Fork、Join操作
Fork
Fork就是一个不断分枝的过程,在当前任务的基础上长出n多个子任务。
当一个ForkJoinTask任务调用fork()方法时,当前线程会把这个任务放入到queue数组的queueTop位置,然后执行以下两句代码:
- if ((s -= queueBase) <= 2)
- pool.signalWork();
- else if (s == m)
- growQueue();
Join
Join是一个不断等待,获取任务执行结果的过程。
- private int doJoin() {
- Thread t; ForkJoinWorkerThread w; int s; boolean completed;
- if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
- if ((s = status) < 0)
- return s;
- if ((w = (ForkJoinWorkerThread)t).unpushTask(this)) {
- try {
- completed = exec();
- } catch (Throwable rex) {
- return setExceptionalCompletion(rex);
- }
- if (completed)
- return setCompletion(NORMAL);
- }
- return w.joinTask(this);
- }
- else
- return externalAwaitDone();
- }
(2)第6行,从queue中取出这个任务来执行,如果执行完了,就设置状态为NORMAL;
(3)前面unpushTask()方法在队列中没有这个任务时会返回false,15行调用joinTask等待这个任务完成。
(4)由于ForkJoinPool中有一个数组叫submissionQueue,通过submit方法调用而且非ForkJoinTask这种任务会被放到这个队列中。这种任务有可能被非ForkJoinWorkerThread线程执行,第18行表示如果是这种任务,等待它执行完成。
下面来看joinTask方法
- final int joinTask(ForkJoinTask<?> joinMe) {
- ForkJoinTask<?> prevJoin = currentJoin;
- currentJoin = joinMe;
- for (int s, retries = MAX_HELP;;) {
- if ((s = joinMe.status) < 0) {
- currentJoin = prevJoin;
- return s;
- }
- if (retries > 0) {
- if (queueTop != queueBase) {
- if (!localHelpJoinTask(joinMe))
- retries = 0; // cannot help
- }
- else if (retries == MAX_HELP >>> 1) {
- --retries; // check uncommon case
- if (tryDeqAndExec(joinMe) >= 0)
- Thread.yield(); // for politeness
- }
- else
- retries = helpJoinTask(joinMe) ? MAX_HELP : retries - 1;
- }
- else {
- retries = MAX_HELP; // restart if not done
- pool.tryAwaitJoin(joinMe);
- }
- }
- }
(2)第20行helpJoinTask()方法返回false时,retries-1,连续8次都没有帮到忙,就会进入第14行,调用yield让权等待。没办法人口太差,想做点好事都不行,只有停下来休息一下。
(3)当执行到第20行,表示自己队列为空,可以去帮助这个任务了,下面来看是怎么帮助的?
- outer:for (ForkJoinWorkerThread thread = this;;) {
- // Try to find v, the stealer of task, by first using hint
- ForkJoinWorkerThread v = ws[thread.stealHint & m];
- if (v == null || v.currentSteal != task) {
- for (int j = 0; ;) { // search array
- if ((v = ws[j]) != null && v.currentSteal == task) {
- thread.stealHint = j;
- break; // save hint for next time
- }
- if (++j > m)
- break outer; // can't find stealer
- }
- }
- // Try to help v, using specialized form of deqTask
- for (;;) {
- ForkJoinTask<?>[] q; int b, i;
- if (joinMe.status < 0)
- break outer;
- if ((b = v.queueBase) == v.queueTop ||
- (q = v.queue) == null ||
- (i = (q.length-1) & b) < 0)
- break; // empty
- long u = (i << ASHIFT) + ABASE;
- ForkJoinTask<?> t = q[i];
- if (task.status < 0)
- break outer; // stale
- if (t != null && v.queueBase == b &&
- UNSAFE.compareAndSwapObject(q, u, t, null)) {
- v.queueBase = b + 1;
- v.stealHint = poolIndex;
- ForkJoinTask<?> ps = currentSteal;
- currentSteal = t;
- t.doExec();
- currentSteal = ps;
- helped = true;
- }
- }
- // Try to descend to find v's stealer
- ForkJoinTask<?> next = v.currentJoin;
- if (--levels > 0 && task.status >= 0 &&
- next != null && next != task) {
- task = next;
- thread = v;
- }
- }
(2)当找到了小偷后,以其人之身还之其人之道,从小偷那里偷任务过来,相当于你和小偷共同执行你的任务,会加速你的任务完成。
(3)小偷也是爷,如果小偷也在等待一个任务完成,权利反转(小偷等待的这个任务做为当前任务,小偷扮演当事人角色把前面的流程走一遍),这是一个递归的过程。
如果你喜欢本文, 请长按二维码,关注公众号 分布式编程.
作者:分布式编程
出处:https://zthinker.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。