Fork/Join框架之Fork、Join操作
来源:互联网 发布:佳能e618清零软件 编辑:程序博客网 时间:2024/04/29 03:48
Fork
Fork就是一个不断分枝的过程,在当前任务的基础上长出n多个子任务。
当一个ForkJoinTask任务调用fork()方法时,当前线程会把这个任务放入到queue数组的queueTop位置,然后执行以下两句代码:
if ((s -= queueBase) <= 2) pool.signalWork();else if (s == m) growQueue();其中s=queueTop,m为数组length减1。else if部分,表示数组所有元素都满了,需要扩容,不难理解。if部分表示当数组元素比较少时(1或者2),就调用signalWork()方法。signalWork()方法做了两件事:1、唤配当前线程;2、当没有活动线程时或者线程数较少时,添加新的线程。
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();}(1)第4行,(s=status)<0表示这个任务被执行完,直接返回执行结果状态,上层捕获到状态后,决定是要获取结果还是进行错误处理;
(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); } }}(1)这里有个常量MAX_HELP=16,表示帮助join的次数。第11行,queueTop!=queueBase表示本地队列中有任务,如果这个任务刚好在队首,则尝试自己执行;否则返回false。这时retries被设置为0,表示不能帮助,因为自已队列不为空,自己并不空闲。在下一次循环就会进入第24行,等待这个任务执行完成。
(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; }}(1)通过查看stealHint这个字段的注释可以知道,它表示最近一次谁来偷过我的queue中的任务。因此通过stealHint并不能找到当前任务被谁偷了?所以第4行v.currentSteal != task完全可能。这时还有一个办法找到这个任务被谁偷了,看看currentSteal这个字段的注释表示最近偷的哪个任务。这里扫描所有偷来的任务与当前任务比较,如果相等,就是这个线程偷的。如果这两种方法都不能找到小偷,只能等待了。
(2)当找到了小偷后,以其人之身还之其人之道,从小偷那里偷任务过来,相当于你和小偷共同执行你的任务,会加速你的任务完成。
(3)小偷也是爷,如果小偷也在等待一个任务完成,权利反转(小偷等待的这个任务做为当前任务,小偷扮演当事人角色把前面的流程走一遍),这是一个递归的过程。
- Fork/Join框架之Fork、Join操作
- Fork/Join框架之Fork、Join操作
- Fork/Join框架之Fork、Join操作
- Fork/join框架之ForkJoinPool
- Fork/join框架之ForkJoinPool
- Fork/Join框架介绍
- Fork/Join框架介绍
- java Fork-join框架
- Fork/Join框架介绍
- Java7 FORK/JOIN框架
- Fork/Join框架
- Fork/Join框架简介
- Fork/Join框架使用
- Fork/Join 框架
- fork/join框架
- Java Fork/join框架
- Fork/Join框架介绍
- Fork/Join框架简介
- (step6.2.2)hdu 1874(畅通工程续——最短路径)
- 黑马程序员——反射知识总结
- js eval函数使用方法介绍
- USB数据线内阻对充电电流的影响
- sicily1687. Permutation
- Fork/Join框架之Fork、Join操作
- HTTP basic 认证
- Android 自定义AutoCompleteTextView实现显示所有项
- 如何在越狱设备ROOT权限下安装APP
- Java基础10:异常;包;
- _ALIGN宏与内存对齐
- Weblogic 验证码无法显示错误解决办法
- 锂电池保护板原理
- 实时性Hadoop