Java并发之ForkJoin

ForkJoin简介

Java7中新添加了一种并发框架ForkJoin.如其名所言,ForkJoin框架适用于将任务分解为子任务,然后将结果合并的场景.

ForkJoin与Executor类似,使用池(ForkJoinPool)来管理线程(ForkJoinWorkerThread),使用队列来管理任务(ForkJoinTask).
不同的是,ForkJoin中使用多个队列来管理任务,并且分为共享队列(偶数)和工作队列(奇数).

共享队列只是用来存储提交的任务.
工作队列会与一个工作者线程ForkJoinWorkerThread绑定.
在工作队列为空时,工作者线程会从其他任务队列(包含共享和工作队列)窃取一个任务来执行.
工作者线程执行并分解任务,其分解的任务,会提交到其对应的工作队列.

ForkJoin工作流程

ForkJoinPool工作流程

ForkJoinPool工作流程如下图:
ForkJoinPool工作流程

步骤说明如下:

1.任务task0被提交到ForkJoinPool池

2.ForkJoinPool池将任务放入共享队列(偶数队列)

3.检查并发等级(活动工作线程数),ForkJoinPool池添加工作队列和工作者线程

4.工作者线程遍历ForkJoinPool池中的任务队列,取出一个任务.

5.工作者线程发现共享队列除了取出的任务外,还有其他任务,通知ForkJoinPool池创建新工作者;然后执行任务(任务执行中可能产生新任务,新任务提交到此线程对应的工作队列);执行任务达到一定数量或工作者队列为空时,尝试等待或退出,不满足条件重复4,5步骤;满足等待,则停止工作,等待唤醒,唤醒后重复4,5步骤;满足退出条件,则退出.

6.ForkJoinPool池根据并发等级等条件创建新工作队列和工作者线程

7.新工作者线程遍历ForkJoinPool池中的队列,取出一个任务;重复步骤5的操作.

线程工作窃取流程

任务在等待子任务完成,即执行subTask.join()时,进行工作窃取.流程如图:
线程工作窃取流程

1.w工作者,在等待currentJoin任务的完成;

2.它遍历工作者队列,发现v工作者在执行此任务(即v.currentSteal == w.currentJoin), 并且v队列的数组中还有其他任务,w则帮助v执行任务,如果w帮助v将队列数组中的任务执行完了,而w等待的currentJoin还没有完成,则w检查v是否在等待其他任务;

3.如果在等待(即v.currentJoin != null),则找到对应执行任务的j(即j.currentSteal == v.currentJoin);不在等待,或没有对应的j,进入步骤5

4.如果j队列的数组中还有其他任务,w则帮助j执行任务;如果没有任务,且j的任务没有执行完成,则检查j是否在等待其他任务,如果有,反复类似3,4操作;

5.否则,w请求睡眠补偿(即w通知池它将睡眠,池启动另一个工作者替代).如果成功,则w睡眠;否则继续遍历工作者队列(如前面ForkJoinPool工作流程中4)

工作者线程睡眠唤醒

工作者线程的睡眠唤醒是通过ForkJoinPool的成员域ctl控制的.
如下图:
工作者线程睡眠唤醒

如前所述,工作者线程是绑定到一个工作队列的.

工作者线程在睡眠前,会将其对应工作队列的scanState写入ctl的低32位.而原ctl中的低32的值会写到工作队列的stackPred中.这样就形成了一个链表.ctl低32位对应最后睡眠的工作者线程t0的工作队列wt0的scanState;而工作队列wt0的stackPred对应在其之前睡眠的工作者线程t1(如果存在)的工作队列wt1的 scanState;依次类推,即可遍历出所有线程睡眠的反序列. 而线程唤醒顺序即为这个反序列.

其他

为了提高性能,在一些小细节上有一些特别的优化.

如,为了判断是否要新建线程,即活动运行工作者数量是否达到了目标并发数,它不是保存活动运行工作者数量,而是保存活动运行工作者数减去目标并发(AC)的数值,这样每次判断时不用再进行减法操作.

还有,它在一些地方使用了延时锁.这样即保证了数据的同步,又减小了同步开销.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值