上篇文章一直追踪到了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. 转:C++学习之Pair

    Pair类型概述 pair是一种模板类型,其中包含两个数据值,两个数据的类型可以不同,基本的定义如下: pair<int, string> a; 表示a中有两个类型,第一个元素是int型的 ...

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

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

  3. LINUX 笔记-wget命令

    使用wget下载单个文件 命令:wget http://www.minjieren.com/wordpress-3.1-zh_CN.zip 使用wget -c断点续传 命令:wget -c http: ...

  4. (原创)(四)机器学习笔记之Scikit Learn的Logistic回归初探

    目录 5.3 使用LogisticRegressionCV进行正则化的 Logistic Regression 参数调优 一.Scikit Learn中有关logistics回归函数的介绍 1. 交叉 ...

  5. sublime text3 开发必备插件

    1,Package Control 通俗易懂地说,这个是你在完成安装SublimeText后必须安装的东西.你问为什么?因为有了这个特殊的"插件包",你可以很容易地安装.升级.删除 ...

  6. oracle赋值问题(将同一表中某一字段赋值给另外一个字段的语句)

    将同一表中某一字段赋值给另外一个字段的语句update jxc_ckmx ckmx1 set ckmx1.ddsl = (select ckmx2.sl from jxc_ckmx ckmx2 whe ...

  7. QT生成PDF文件

    QString temp=""; //m_File_Content_Text_Edit->selectAll(); QString t_File_Content = m_Fi ...

  8. 2456: mode

    2456: mode Time Limit: 1 Sec  Memory Limit: 1 MBSubmit: 4798  Solved: 2009[Submit][Status][Discuss] ...

  9. 一款超好用轻量级JS框架——Zepto.js(上)

       前  言 絮叨絮叨 之前我们介绍过JQuery怎么自定义一个插件,但没有详细介绍过JQuery,那么今天呢....我们还是不说JQuery,哈哈哈哈 但是今天我们介绍一款和JQuery超级像的一 ...

  10. Node.js 回调函数

    Node.js 回调函数 Node.js 异步编程的直接体现就是回调. 异步编程依托于回调来实现,但不能说使用了回调后程序就异步化了. 回调函数在完成任务后就会被调用,Node 使用了大量的回调函数, ...