[JAVA学习笔记-51]ForkJoin
来源:互联网 发布:java项目收获总结 编辑:程序博客网 时间:2024/06/03 18:56
【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线程执行完毕,然后返回结果
【真实的例子】
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线程执行完毕,然后返回结果
【真实的例子】
0 0
- [JAVA学习笔记-51]ForkJoin
- JAVA 7 ForkJoin学习笔记
- JAVA7 的ForkJoin框架-学习笔记
- java并发编程学习4--forkJoin
- 学习笔记之Java7中的ForkJoin并发框架初探(下)—— ForkJoin的应用
- Java并发之ForkJoin
- ForkJoin
- ForkJoin
- forkjoin
- java8学习第三篇:forkjoin
- java.util.concurrent之ForkJoin
- Java并发 Thread、Executor、ForkJoin和Actor
- java多线程之并行框架ForkJoin
- Java并发的四种口味:Thread、Executor、ForkJoin、Actor
- java 7 forkjoin并行框架的源码详究
- Java多线程编程简明教程(2) - ForkJoin模式
- java ForkJoin框架实现统计词频性能比较
- ForkJoin框架
- Codeforces-731D-data structure
- ElasticSearch之旅--常用语法
- 使用jquery实现全选
- (转载)Android属性动画完全解析(上),初识属性动画的基本用法
- 栈区和堆区的区别
- [JAVA学习笔记-51]ForkJoin
- log4j日志输出控制
- 1.VMware软件介绍
- iOS10中 info.plist添加需要权限对应的字段
- IOS10.1真机调试
- 开发一款数字货币
- LeetCode解题记录
- SpringBoot在线程中获取容器中的Bean
- 索引结点的总结