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的优势,把一个任务拆分成多个“小任务”,把多个“小任务”放到多个处理器核心上并行执行:当多个“小任务”执行完成之后,再将这些执行结果 ...
随机推荐
- 【AtCoder】【模型转化】【二分答案】Median Pyramid Hard(AGC006)
题意: 给你一个排列,有2*n-1个元素,现在进行以下的操作: 每一次将a[i]替换成为a[i-1],a[i],a[i+1]三个数的中位数,并且所有的操作是同时进行的,也就是说这一次用于计算的a[], ...
- asp 获取url 返回值 和 对json 返回值的处理
Function GetHttpPage(HttpUrl,endoce) If endoce = "" Then endoce = "GB2312" If Is ...
- Python3的桌面程序开发利器:Eric6的环境搭建、使用
本文旨在通过一个简单的demo,介绍基于Python3.PyQT5的环境下开发桌面应用程序的一种方案,当然开发Python的桌面应用程序不止是PyQT 这一种方案,还可以使用Python自带的Tkin ...
- React(三)JSX内置表达式
(一)JSX是什么? React 使用 JSX 来替代常规的 JavaScript. JSX 是一个看起来很像 XML 的 JavaScript 语法扩展. 我们不需要一定使用 JSX,但它有以下优点 ...
- 高性能平滑动画_requestAnimationFrame
高性能平滑动画_requestAnimationFrame 在下一次重绘之前,执行一个函数
- [LeetCode] Smallest Rotation with Highest Score 得到最高分的最小旋转
Given an array A, we may rotate it by a non-negative integer K so that the array becomes A[K], A[K+1 ...
- sql的基础用法
# sql 对大小写不敏感 # 查询表中的所有信息 select * from `Customers`; # 查询指定字段 CustomerName,Country select CustomerNa ...
- HDFS基础配置
HADOOP-3.1.0-----HDFS基础配置 执行步骤:(1)配置集群(2)启动.测试集群增.删.查(3)执行wordcount案例 一.配置集群 1.在 hadoop-env.sh配置文件添加 ...
- NSTextField/NSTextView中显示超链接以及NSMutableAttributedString用法
扩展NSAttributedString 简单的实现方法是为NSAttributedString 添加一个category. 然后为此category添加额外的方法. 具体实现如下: [代码]c#/c ...
- mysql 日志类型
mysql有四种日志: 所有日志:general log 慢查询日志:slow log 二进制日志:binary log 错误日志:error log windows下在my.ini里配置,linux ...