上篇文章一直追踪到了ForkJoinWorkerThread的pushTask方法,仍然没有办法解释Fork的原理,那么不妨来看看ForkJoinWorkerThread的run方法:

    public void run() {
Throwable exception = null;
try {
// 初始化任务队列
onStart();
// 线程运行
pool.work(this);
} catch (Throwable ex) {
exception = ex;
} finally {
// 结束后的工作
onTermination(exception);
}
}

因此我们需要再次回到ForkJoinPool,看看work方法:

    final void work(ForkJoinWorkerThread w) {
boolean swept = false; // 下面scan方法没有扫描到任务返回true
long c;
// ctl是一个64位长的数据,它的格式如下:
// 48-63:AC,正在运行的worker线程数减去系统的并发数(减去系统的并发得出的实际是在某一瞬间等待并发资源的线程数量)
// 32-47:TC,所有的worker线程数减去系统的并发数
// 31: ST,1表示线程池正在关闭
// 16-30:EC,第一个等待线程的等待数
// 0- 15:ID,Treiber栈(存储等待线程)顶的worker线程在线程池的线程队列中的索引
// (int)(c = ctl) >= 0表示ST位为0,即线程池不是正在关闭的状态
while (!w.terminate && (int)(c = ctl) >= 0) {
int a; // 正在运行的worker线程数,ctl中的AC部分
// swept为false可能有三种:
// 1. scan返回false
// 2. 首次循环
// 3. tryAwaitWork成功
if (!swept && (a = (int)(c >> AC_SHIFT)) <= 0)
swept = scan(w, a);
else if (tryAwaitWork(w, c))
swept = false;
}
}

接下来分析scan方法,我承认我看得有点晕。

    private boolean scan(ForkJoinWorkerThread w, int a) {
int g = scanGuard; // mask 0 avoids useless scans if only one active
int m = (parallelism == 1 - a && blockedCount == 0) ? 0 : g & SMASK;
ForkJoinWorkerThread[] ws = workers;
if (ws == null || ws.length <= m) // staleness check
return false;
// 代码看起来晕啊,看来当前的ForkJoinWorkerThread不一定是运行自己的
// Task,可以运行其他ForkJoinWorkerThread的Task。
// 似乎有点明白了,这样可以实现Fork出来的任务被多线程执行
// 看起来这是一个较为复杂的算法
for (int r = w.seed, k = r, j = -(m + m); j <= m + m; ++j) {
ForkJoinTask<?> t; ForkJoinTask<?>[] q; int b, i;
ForkJoinWorkerThread v = ws[k & m];
if (v != null && (b = v.queueBase) != v.queueTop &&
(q = v.queue) != null && (i = (q.length - 1) & b) >= 0) {
long u = (i << ASHIFT) + ABASE;
if ((t = q[i]) != null && v.queueBase == b &&
UNSAFE.compareAndSwapObject(q, u, t, null)) {
int d = (v.queueBase = b + 1) - v.queueTop;
v.stealHint = w.poolIndex;
if (d != 0)
signalWork(); // propagate if nonempty
w.execTask(t);
}
r ^= r << 13; r ^= r >>> 17; w.seed = r ^ (r << 5);
return false; // store next seed
}
else if (j < 0) { // xorshift
r ^= r << 13; r ^= r >>> 17; k = r ^= r << 5;
}
else
++k;
}
if (scanGuard != g) // staleness check
return false;
else { // try to take submission
ForkJoinTask<?> t; ForkJoinTask<?>[] q; int b, i;
if ((b = queueBase) != queueTop &&
(q = submissionQueue) != null &&
(i = (q.length - 1) & b) >= 0) {
long u = (i << ASHIFT) + ABASE;
if ((t = q[i]) != null && queueBase == b &&
UNSAFE.compareAndSwapObject(q, u, t, null)) {
queueBase = b + 1;
w.execTask(t);
}
return false;
}
return true; // all queues empty
}
}

但是起码能看出来,Fork出来的任务是如何被其他线程运行以实现多线程运行的了。面对这么个有点复杂的算法,我只能先去查查,发现原来叫做Work-Stealing,好吧,下一篇来研究这个Work-Stealing。

《java.util.concurrent 包源码阅读》23 Fork/Join框架之Fork的冰山一角的更多相关文章

  1. 《java.util.concurrent 包源码阅读》 结束语

    <java.util.concurrent 包源码阅读>系列文章已经全部写完了.开始的几篇文章是根据自己的读书笔记整理出来的(当时只阅读了部分的源代码),后面的大部分都是一边读源代码,一边 ...

  2. 《java.util.concurrent 包源码阅读》13 线程池系列之ThreadPoolExecutor 第三部分

    这一部分来说说线程池如何进行状态控制,即线程池的开启和关闭. 先来说说线程池的开启,这部分来看ThreadPoolExecutor构造方法: public ThreadPoolExecutor(int ...

  3. 《java.util.concurrent 包源码阅读》02 关于java.util.concurrent.atomic包

    Aomic数据类型有四种类型:AomicBoolean, AomicInteger, AomicLong, 和AomicReferrence(针对Object的)以及它们的数组类型, 还有一个特殊的A ...

  4. 《java.util.concurrent 包源码阅读》04 ConcurrentMap

    Java集合框架中的Map类型的数据结构是非线程安全,在多线程环境中使用时需要手动进行线程同步.因此在java.util.concurrent包中提供了一个线程安全版本的Map类型数据结构:Concu ...

  5. 《java.util.concurrent 包源码阅读》17 信号量 Semaphore

    学过操作系统的朋友都知道信号量,在java.util.concurrent包中也有一个关于信号量的实现:Semaphore. 从代码实现的角度来说,信号量与锁很类似,可以看成是一个有限的共享锁,即只能 ...

  6. 《java.util.concurrent 包源码阅读》06 ArrayBlockingQueue

    对于BlockingQueue的具体实现,主要关注的有两点:线程安全的实现和阻塞操作的实现.所以分析ArrayBlockingQueue也是基于这两点. 对于线程安全来说,所有的添加元素的方法和拿走元 ...

  7. 《java.util.concurrent 包源码阅读》22 Fork/Join框架的初体验

    JDK7引入了Fork/Join框架,所谓Fork/Join框架,个人解释:Fork分解任务成独立的子任务,用多线程去执行这些子任务,Join合并子任务的结果.这样就能使用多线程的方式来执行一个任务. ...

  8. 《java.util.concurrent 包源码阅读》09 线程池系列之介绍篇

    concurrent包中Executor接口的主要类的关系图如下: Executor接口非常单一,就是执行一个Runnable的命令. public interface Executor { void ...

  9. 《java.util.concurrent 包源码阅读》24 Fork/Join框架之Work-Stealing

    仔细看了Doug Lea的那篇文章:A Java Fork/Join Framework 中关于Work-Stealing的部分,下面列出该算法的要点(基本是原文的翻译): 1. 每个Worker线程 ...

  10. 《java.util.concurrent 包源码阅读》25 Fork/Join框架之Fork与Work-Stealing(重写23,24)

    在写前面两篇文章23和24的时候自己有很多细节搞得不是很明白,这篇文章把Fork和Work-Stealing相关的源代码重新梳理一下. 首先来看一些线程池定义的成员变量: 关于scanGuard: v ...

随机推荐

  1. JavaScript之“创意时钟”项目

    “时钟展示项目”说明文档(文档尾部附有相应代码) 一.最终效果展示: 二.项目亮点 1.代码结构清晰明了 2.可以实时动态显示当前时间与当前日期 3.界面简洁.美观.大方 4.提高浏览器兼容性 三.知 ...

  2. 见到过的MOS管的一些参数

    选择MOS管的时候需要注意的几个参数1,VDSS(击穿电压):此电压要选择合适,一般是加入的电压值的峰值的两倍.2,VGS(th)(开启电压):3,RDS(on)(漏源电阻):这个值要尽可能的小,因为 ...

  3. Android 6.0 双向通话自动录音

    package com.example.hgx.phoneinfo60.Recording; import android.content.BroadcastReceiver; import andr ...

  4. Django——模板层(template)(模板语法、自定义模板过滤器及标签、模板继承)

    前言:当我们想在页面上给客户端返回一个当前时间,一些初学者可能会很自然的想到用占位符,字符串拼接来达到我们想要的效果,但是这样做会有一个问题,HTML被直接硬编码在 Python代码之中. 1 2 3 ...

  5. LINUX 笔记之常用打包压缩命令

    1.将所有.jpg文件打成一个名为all.tar的包 tar -cf all.tar *.gif 2.将所有.gif文件追加到all.tar tar -rf all.tar *.gif 3.更新原来t ...

  6. 磨刀不误砍柴工!vs2010快捷键大全

    最常用的快捷键: VS2012变化的快捷键: 注释::VS2010是(Ctrl+E,C),VS2012是(Ctrl+K, Ctrl+C),实际操作,按住Ctrl键不放,先按K键,再按C键.相当于Ctr ...

  7. Peaceful Commission

    Peaceful Commission Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...

  8. Turn the corner

    Turn the corner Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tot ...

  9. JS模块化-requireJS

    1. 为什么要使用require.js 刚开始的时候,网页需要用到很多不同的插件,都是依次加载,需要注意其中的加载顺序即依赖关系. <script src="1.js"> ...

  10. easyui dialog 中嵌入html页面

    最近使用easyui比较多,这个插件确实很好用.在使用时也遇到了大大小小的问题,好在都一一解决了. 记录一下今天遇到的问题. 目的:用easyui的dialog嵌入一个html页面(html中仍有要执 ...