• fork():开启一个新线程(或是重用线程池内的空闲线程),将任务交给该线程处理。
  • join():等待该任务的处理线程处理完毕,获得返回值。

ForkJoinPool 的每个工作线程都维护着一个工作队列WorkQueue),这是一个双端队列(Deque),里面存放的对象是任务ForkJoinTask)。

每个工作线程在运行中产生新的任务(通常是因为调用了 fork())时,会放入工作队列的队尾,并且工作线程在处理自己的工作队列时,使用的是 LIFO 方式,也就是说每次从队尾取出任务来执行。

每个工作线程在处理自己的工作队列同时,会尝试窃取一个任务(或是来自于刚刚提交到 pool 的任务,或是来自于其他工作线程的工作队列),窃取的任务位于其他线程的工作队列的队首,也就是说工作线程在窃取其他工作线程的任务时,使用的是 FIFO 方式。

在遇到 join() 时,如果需要 join 的任务尚未完成,则会先处理其他任务,并等待其完成。

在既没有自己的任务,也没有可以窃取的任务时,进入休眠。

fork

fork() 做的工作只有一件事,既是把任务推入当前工作线程的工作队列里。可以参看以下的源代码:

join

join() 的工作则复杂得多,也是 join() 可以使得线程免于被阻塞的原因——不像同名的 Thread.join()

1.检查调用 join() 的线程是否是 ForkJoinThread 线程。如果不是(例如 main 线程),则阻塞当前线程,等待任务完成。如果是,则不阻塞。

2.查看任务的完成状态,如果已经完成,直接返回结果。

3.如果任务尚未完成,但处于自己的工作队列内,则完成它。

4.如果任务已经被其他的工作线程偷走,则窃取这个小偷的工作队列内的任务(以 FIFO 方式),执行,以期帮助它早日完成欲 join 的任务。

5.如果偷走任务的小偷也已经把自己的任务全部做完,正在等待需要 join 的任务时,则找到小偷的小偷,帮助它完成它的任务。

6.递归地执行第5步。

以上就是 fork()join() 的原理,这可以解释 ForkJoinPool 在递归过程中的执行逻辑,但还有一个问题

最初的任务是 push 到哪个线程的工作队列里的?

这就涉及到 submit() 函数的实现方法了

其实除了前面介绍过的每个工作线程自己拥有的工作队列以外,ForkJoinPool 自身也拥有工作队列,这些工作队列的作用是用来接收由外部线程(非 ForkJoinThread 线程)提交过来的任务,而这些工作队列被称为 submitting queue

submit()fork() 其实没有本质区别,只是提交对象变成了 submitting queue 而已(还有一些同步,初始化的操作)。submitting queue 和其他 work queue 一样,是工作线程”窃取“的对象,因此当其中的任务被一个工作线程成功窃取时,就意味着提交的任务真正开始进入执行阶段。

ForkJoinPool的更多相关文章

  1. 0041 Java学习笔记-多线程-线程池、ForkJoinPool、ThreadLocal

    什么是线程池 创建线程,因为涉及到跟操作系统交互,比较耗费资源.如果要创建大量的线程,而每个线程的生存期又很短,这时候就应该使用线程池了,就像数据库的连接池一样,预先开启一定数量的线程,有任务了就将任 ...

  2. 【转】线程及同步的性能 - 线程池 / ThreadPoolExecutors / ForkJoinPool

    线程池和ThreadPoolExecutors 虽然在程序中可以直接使用Thread类型来进行线程操作,但是更多的情况是使用线程池,尤其是在Java EE应用服务器中,一般会使用若干个线程池来处理来自 ...

  3. ForkJoinPool 源码

    ForkJoinPool----FJP先看task.fork方法,含义是将当前任务,放到当前线程的工作队列中.但是第一次执行这个方法是在主线程中,主线程是不可能被FJP管理的.那么就进入ForkJoi ...

  4. [原创] JAVA 递归线程池测试 ExecutorService / ForkJoinPool

    测试工具使用递归的方式获取子进程的Msg消息,目前有2种常用的ExecutorService / ForkJoinPool 为了测试哪种效果较好,我们来写个测试Demo,循环5555555次+1(加锁 ...

  5. [Java并发编程(二)] 线程池 FixedThreadPool、CachedThreadPool、ForkJoinPool?为后台任务选择合适的 Java executors

    [Java并发编程(二)] 线程池 FixedThreadPool.CachedThreadPool.ForkJoinPool?为后台任务选择合适的 Java executors ... 摘要 Jav ...

  6. (四)juc线程高级特性——线程池 / 线程调度 / ForkJoinPool

    13. 线程池 第四种获取线程的方法:线程池,一个 ExecutorService,它使用可能的几个池线程之一执行每个提交的任务,通常使用 Executors 工厂方法配置. 线程池可以解决两个不同问 ...

  7. Java并发——Fork/Join框架与ForkJoinPool

    为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/ShiJiaqi. http://www.cnblogs.com/shijiaqi1066/p/4631466. ...

  8. 多线程 ForkJoinPool

    阅读目录 使用 背景:ForkJoinPool的优势在于,可以充分利用多cpu,多核cpu的优势,把一个任务拆分成多个“小任务”,把多个“小任务”放到多个处理器核心上并行执行:当多个“小任务”执行完成 ...

  9. Java 多线程中的任务分解机制-ForkJoinPool,以及CompletableFuture

    ForkJoinPool的优势在于,可以充分利用多cpu,多核cpu的优势,把一个任务拆分成多个“小任务”,把多个“小任务”放到多个处理器核心上并行执行:当多个“小任务”执行完成之后,再将这些执行结果 ...

随机推荐

  1. python学习:删除空白

    删除空白   删除尾部空白 确保字符串尾部没有空白,使用rstrip(); 删除字符串开头的空白,使用lstrip(); 同时删除字符串两端的空白,使用strip() 代码: >>> ...

  2. python语法_元组

    tuple 元组 被称为只读列表 tup = (1,3,4,'234') 只能读,不能进行修改操作. 与列表的区分就是 () [] 中括号和小括号的区别,

  3. iOS—使用picker View

    iOS—使用picker View 一.实现效果 说明:点击随机按钮,能够自动选取,下方数据自动刷新. 二.实现思路 1.picker view的有默认高度为162,不可修改. 2.显示数据,需要设置 ...

  4. 在区块链侧链上进行Dapp技术开发

    我在白皮书里提到过,asch使用的是不同于以太坊和比特币的侧链架构,dapp是运行在侧链上的,每套侧链对应一个dapp. 侧链的独立性 侧链架构的好处是代码和数据独立,不增加主链的负担,避免数据过度膨 ...

  5. 电子产品使用感受之——为什么我那么喜欢2015年的11.6寸MacBook Air?

    2018年Mac笔记本产品线得到了一次更新,Mac book Pro, MacBook Air更新后的Mac 产品线变得更加让人摸不着头脑,价格昂贵不说,产品分类细化到如此程度,让一个选择困难症的消费 ...

  6. POJ 2533 - Longest Ordered Subsequence - [最长递增子序列长度][LIS问题]

    题目链接:http://poj.org/problem?id=2533 Time Limit: 2000MS Memory Limit: 65536K Description A numeric se ...

  7. 使用sysbench压测磁盘io

    Ⅰ.sysbench安装 cd /usr/local/src yum -y install make automake libtool pkgconfig libaio-devel git clone ...

  8. [daily][emacs][go] 配置emacs go-mode的编辑环境以及环境变量问题

    1. 安装go 安装go-mode 使用emacs编辑go代码的时候,你需要有正常可运行的go环境. 并且有emacs的go-mode package https://www.emacswiki.or ...

  9. Android创建列表并为列表添加数据

    在Android开发中经常会用到ListView,也就是列表,而列表的内容需要如何决定呢,很好的方法是使用各种adapter 首先来看看用entries添加列表内容 在布局文件中,创建一个ListVi ...

  10. react-router@4.0 使用和源码解析

    如果你已经是一个正在开发中的react应用,想要引入更好的管理路由功能.那么,react-router是你最好的选择~react-router版本现今已经到4.0.0了,而上一个稳定版本还是2.8.1 ...