ForkJoinPool
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的更多相关文章
- 0041 Java学习笔记-多线程-线程池、ForkJoinPool、ThreadLocal
什么是线程池 创建线程,因为涉及到跟操作系统交互,比较耗费资源.如果要创建大量的线程,而每个线程的生存期又很短,这时候就应该使用线程池了,就像数据库的连接池一样,预先开启一定数量的线程,有任务了就将任 ...
- 【转】线程及同步的性能 - 线程池 / ThreadPoolExecutors / ForkJoinPool
线程池和ThreadPoolExecutors 虽然在程序中可以直接使用Thread类型来进行线程操作,但是更多的情况是使用线程池,尤其是在Java EE应用服务器中,一般会使用若干个线程池来处理来自 ...
- ForkJoinPool 源码
ForkJoinPool----FJP先看task.fork方法,含义是将当前任务,放到当前线程的工作队列中.但是第一次执行这个方法是在主线程中,主线程是不可能被FJP管理的.那么就进入ForkJoi ...
- [原创] JAVA 递归线程池测试 ExecutorService / ForkJoinPool
测试工具使用递归的方式获取子进程的Msg消息,目前有2种常用的ExecutorService / ForkJoinPool 为了测试哪种效果较好,我们来写个测试Demo,循环5555555次+1(加锁 ...
- [Java并发编程(二)] 线程池 FixedThreadPool、CachedThreadPool、ForkJoinPool?为后台任务选择合适的 Java executors
[Java并发编程(二)] 线程池 FixedThreadPool.CachedThreadPool.ForkJoinPool?为后台任务选择合适的 Java executors ... 摘要 Jav ...
- (四)juc线程高级特性——线程池 / 线程调度 / ForkJoinPool
13. 线程池 第四种获取线程的方法:线程池,一个 ExecutorService,它使用可能的几个池线程之一执行每个提交的任务,通常使用 Executors 工厂方法配置. 线程池可以解决两个不同问 ...
- Java并发——Fork/Join框架与ForkJoinPool
为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/ShiJiaqi. http://www.cnblogs.com/shijiaqi1066/p/4631466. ...
- 多线程 ForkJoinPool
阅读目录 使用 背景:ForkJoinPool的优势在于,可以充分利用多cpu,多核cpu的优势,把一个任务拆分成多个“小任务”,把多个“小任务”放到多个处理器核心上并行执行:当多个“小任务”执行完成 ...
- Java 多线程中的任务分解机制-ForkJoinPool,以及CompletableFuture
ForkJoinPool的优势在于,可以充分利用多cpu,多核cpu的优势,把一个任务拆分成多个“小任务”,把多个“小任务”放到多个处理器核心上并行执行:当多个“小任务”执行完成之后,再将这些执行结果 ...
随机推荐
- LeetCode(21. 合并两个有序链表)
问题描述 将两个有序链表合并为一个新的有序链表并返回.新链表是通过拼接给定的两个链表的所有节点组成的. 示例: 输入:1->2->4, 1->3->4 输出:1->1-& ...
- Python: 你不知道的 super
https://segmentfault.com/a/1190000007426467 Python: 你不知道的 super 在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我 ...
- JS_ Date对象应用实例
一.获取日期时间,秒数实时跳动 <!DOCTYPE html> <html lang="en"> <head> <meta charset ...
- 05_ switch 练习 _ 今天星期几
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...
- Web Service学习(一)
1.WebMethod特性包含哪些属性,都有什么用? 1.BufferResponse属性 该属性表明是否启用对Web Service方法响应的缓冲.当设置为true时,Web Service方法将响 ...
- Facebook AI的工业级NLP开源框架—— Pytext
PyText是基于NLP深度学习技术.通过Pytorch构建的建模框架.PyText解决了既要实现快速实验又要部署大规模服务模型的经常相互冲突.并且,Facebook已经采用了使用PyText快速迭代 ...
- Python---函数的相关知识点总结一:
1:定义函数 def printInfo(): print("I love Python!") #调用函数 #注意:函数定义完毕并不会被默认执行,只能通过调用的方式来让它执行 pr ...
- Win10安装和配置JDK
方法/步骤 1.JDK下载 JDK下载可以在官网下载,如图所示,但由于是国外网站,往往下载速度比较慢,所以推荐在百度软件中心下载.这里要注意自己电脑是32位还是64位,根据具体情况下载相应安装包. ...
- 使用re开发python计算器
#!/usr/bin/env python import reimport functools def minus_operator_handler(formula): '''处理一些特殊的减号运算' ...
- TCP/IP协议 数据链路层
以太网 1.以太网(Ethernet)是一种计算机局域网技术,由Xerox.Intel公司在1982年联合开发的技术规范. 2.IEEE组织的IEEE 802.3标准制定了以太网的技术标准,它规定了包 ...