Fork/Join中的调用原理
来源:互联网 发布:maya软件价格 编辑:程序博客网 时间:2024/05/23 01:59
错误程序
public class Calculator extends RecursiveTask { private static final int THRESHOLD = 100; private int start; private int end; public Calculator(int start, int end) { this.start = start; this.end = end; } @Override protected Integer compute() { int sum = 0; if((start - end) < THRESHOLD){ for(int i = start; i< end;i++){ sum += i; } }else{ int middle = (start + end) /2; Calculator left = new Calculator(start, middle); Calculator right = new Calculator(middle + 1, end); left.fork(); right.fork(); sum = left.join() + right.join(); } return sum; } }
(1)fork
1.基本作用
将任务放入任务队列队尾
2.源码
public final ForkJoinTask<V> fork() { ((ForkJoinWorkerThread) Thread.currentThread()) .pushTask(this); return this; }该方法属于:ForkJoinTask,也就是说this指向任务本身,将任务添加到任务队列末尾
因为运行ForkJoinTask的线程就是ForkJoinWorkerThread,所以可以调用其中的pushTask方法
/** * Pushes a task. Call only from this thread. * * @param t the task. Caller must ensure non-null. */ final void pushTask(ForkJoinTask<?> t) { ForkJoinTask<?>[] q; int s, m; if ((q = queue) != null) { // ignore if queue removed long u = (((s = queueTop) & (m = q.length - 1)) << ASHIFT) + ABASE; UNSAFE.putOrderedObject(q, u, t); queueTop = s + 1; // or use putOrderedInt if ((s -= queueBase) <= 2) pool.signalWork(); else if (s == m) //扩容用 growQueue(); } }其中有个成员变量queue,用来存储和本线程对应的任务队列
定义:
ForkJoinTask<?>[] queue;
初始化:
protected void onStart() { queue = new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY]; .... }接着继续看pushTask
if ((s -= queueBase) <= 2) pool.signalWork();就是说当任务队列中只有一个任务时,从线程池中调用线程执行
(2)join
1.基本作用
阻塞当前线程,直到本任务执行完毕(相当于ForkJoinTask版的Thread.join)
2.源码
public final V join() { if (doJoin() != NORMAL) return reportResult(); else return getRawResult(); }主要是为了看返回值,接着看doJoin
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(); }这里先通过status判断状态
volatile int status; // accessed directly by pool and workers private static final int NORMAL = -1; private static final int CANCELLED = -2; private static final int EXCEPTIONAL = -3; private static final int SIGNAL = 1;也就是说<0的是已经执行完毕的,这对于窃取非常重要
然后通过unpushTask取任务然后执行,看下unpushTask
final boolean unpushTask(ForkJoinTask<?> t) { ForkJoinTask<?>[] q; int s; if ((q = queue) != null && (s = queueTop) != queueBase && UNSAFE.compareAndSwapObject (q, (((q.length - 1) & --s) << ASHIFT) + ABASE, t, null)) { queueTop = s; // or putOrderedInt return true; } return false; }注意其中的--s,也就是说是从队列尾取的任务
(3)分析
left.fork(); right.fork(); sum = left.join() + right.join();由上面可知,这段代码的意思就是:
1.把left放入任务队列,right放入任务队列。此时right在队尾,left在倒数第二个
2.left.join(),因为当前right在队尾,所以说取不出来!!!因而线程就会阻塞
正确的是调用invokeAll,看下invokeAll
public static void invokeAll(ForkJoinTask<?> t1, ForkJoinTask<?> t2) { t2.fork(); t1.invoke(); t2.join(); }也就是说先把t2加入队列中,然后直接执行t1,接着对t2执行join
对应上例就是:把right放入队列尾部,然后left开始执行,最后对right进行join,直到left执行完毕才能执行(当然right可能被其他线程窃取,这样通过状态判断就直接返回了)
更一般的
public static void invokeAll(ForkJoinTask<?>... tasks) { Throwable ex = null; int last = tasks.length - 1; for (int i = last; i >= 0; --i) { ForkJoinTask<?> t = tasks[i]; if (t == null) { if (ex == null) ex = new NullPointerException(); } else if (i != 0) t.fork(); else if (t.doInvoke() < NORMAL && ex == null) ex = t.getException(); } for (int i = 1; i <= last; ++i) { ForkJoinTask<?> t = tasks[i]; if (t != null) { if (ex != null) t.cancel(false); else if (t.doJoin() < NORMAL && ex == null) ex = t.getException(); } } if (ex != null) UNSAFE.throwException(ex); }可以看到 i != 0 才进行fork,也就是说队列中第一个都是直接执行的,其他的以此fork,fork之后的任务之后进行join
(4)invoke
1.基本作用
直接执行任务
2.源码
public final V invoke() { if (doInvoke() != NORMAL) return reportResult(); else return getRawResult(); }再看下doInvoke
private int doInvoke() { int s; boolean completed; if ((s = status) < 0) return s; try { completed = exec(); } catch (Throwable rex) { return setExceptionalCompletion(rex); } if (completed) return setCompletion(NORMAL); else return doJoin(); }其中的exec()在RecursiveTask中
protected final boolean exec() { result = compute(); return true; }在RecursiveAction中
protected final boolean exec() { compute(); return true; }也就是说直接执行了
- Fork/Join中的调用原理
- Fork/Join中的API
- java7 、Fork/Join 框架原理
- JDK7中的Fork/Join模式
- Fork/Join中的异常处理
- JAVA中的Fork/Join框架
- Fork/Join 实战中的实例
- java7中的fork join框架
- java7中的fork/join框架
- JDK 7 中的 Fork/Join 模式
- JDK 7 中的 Fork/Join 模式
- JDK 7 中的 Fork/Join 模式
- JDK 7 中的 Fork/Join 模式
- JDK 7 中的 Fork/Join 模式
- JDK 7中的 Fork/Join模式
- JDK 7 中的 Fork/Join 模式
- JDK 7 中的 Fork/Join 模式
- JDK 7 中的 Fork/Join 模式
- windows环境下搭建DB2 单物理节点 DPF 数据库
- jq响应式布局并计数
- Python xrange与range的区别
- Android比iOS卡得原因和本质区别总结
- hibernate的注解
- Fork/Join中的调用原理
- Android studio 默认快捷键
- tail -f 查看多个日志文件
- UVA10763-交换生
- css3-渐变
- Android Studio failed to find build tools revision 19.1.0 问题
- iOS —— ARC、MRC 下dealloc 方法存在的意义
- php 日期转成数字
- 【LeetCode】119Pascal's Triangle II