一、概览

Fork/Join并行方式是获取良好的并行计算性能的一种最简单同时也是最有效的设计技术。Fork/Join并行算法是我们所熟悉的分治算法的并行版本,典型的用法如下:

Result solve(Problem problem) {if (problem is small) {directly solve problem} else {split problem into independent partsfork new subtasks to solve each partjoin all subtaskscompose result from subresults}
}

fork操作将会启动一个新的并行Fork/Join子任务。join操作会一直等待直到所有的子任务都结束。Fork/Join算法,如同其他分治算法一样,总是会递归的、反复的划分子任务,直到这些子任务可以用足够简单的、短小的顺序方法来执行。

下图来自:https://segmentfault.com/a/1190000008140126

        可以看出核心操作有以下几点:

  1. fork
  2. join
  3. 线程池

二、Fork

将任务压入workQueue

    public final ForkJoinTask<V> fork() {Thread t;if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)((ForkJoinWorkerThread)t).workQueue.push(this);elseForkJoinPool.common.externalPush(this);return this;}

三、Join

等待任务结束或中断

    public final V join() {int s;if ((s = doJoin() & DONE_MASK) != NORMAL)reportException(s);return getRawResult();}

四、线程池与work−stealing算法

  • 每一个工作线程维护自己的调度队列中的可运行任务。
  • 队列以双端队列的形式被维护(注:deques通常读作『decks』),不仅支持后进先出 —— LIFO的push和pop操作,还支持先进先出 —— FIFO的take操作。
  • 对于一个给定的工作线程来说,任务所产生的子任务将会被放入到工作者自己的双端队列中。
  • 工作线程使用后进先出 —— LIFO(最新的元素优先)的顺序,通过弹出任务来处理队列中的任务。
  • 当一个工作线程的本地没有任务去运行的时候,它将使用先进先出 —— FIFO的规则尝试随机的从别的工作线程中拿(『窃取』)一个任务去运行。
  • 当一个工作线程触及了join操作,如果可能的话它将处理其他任务,直到目标任务被告知已经结束(通过isDone方法)。所有的任务都会无阻塞的完成。
  • 当一个工作线程无法再从其他线程中获取任务和失败处理的时候,它就会退出(通过yield、sleep和/或者优先级调整,参考第3节)并经过一段时间之后再度尝试直到所有的工作线程都被告知他们都处于空闲的状态。在这种情况下,他们都会阻塞直到其他的任务再度被上层调用。
  • 使用后进先出 —— LIFO用来处理每个工作线程的自己任务,但是使用先进先出 —— FIFO规则用于获取别的任务,这是一种被广泛使用的进行递归Fork/Join设计的一种调优手段。引用[5]讨论了详细讨论了里面的细节。

让窃取任务的线程从队列拥有者相反的方向进行操作会减少线程竞争。同样体现了递归分治算法的大任务优先策略。因此,更早期被窃取的任务有可能会提供一个更大的单元任务,从而使得窃取线程能够在将来进行递归分解。

作为上述规则的一个后果,对于一些基础的操作而言,使用相对较小粒度的任务比那些仅仅使用粗粒度划分的任务以及那些没有使用递归分解的任务的运行速度要快。尽管相关的少数任务在大多数的Fork/Join框架中会被其他工作线程窃取,但是创建许多组织良好的任务意味着只要有一个工作线程处于可运行的状态,那么这个任务就有可能被执行。

Work-Stealing 的适用场景是不同的任务的耗时相差比较大,即某些任务需要运行较长时间,而某些任务会很快的运行完成,这种情况下用 Work-Stealing 很合适;但是如果任务的耗时很平均,则此时 Work-Stealing 并不适合,因为窃取任务时不同线程需要抢占锁,这可能会造成额外的时间消耗,而且每个线程维护双端队列也会造成更大的内存消耗。所以 ForkJoinPool 并不是 ThreadPoolExecutor 的替代品,而是作为对 ThreadPoolExecutor 的补充。

五、协程

其实早在JDK1的时代,Java的线程被称为GreenThread,那个时候就已经有了Fiber,但是当时不能与操作系统实现N:M绑定,所以放弃了。现在Quasar凭借ForkJoinPool这个成熟的线程调度库。另外,如果你希望你的代码能够跑在Fiber里面,需要一个很大的前提条件,那就是你所有的库,必须是异步无阻塞的,也就说必须类似于node.js上的库,所有的逻辑都是异步回调,而自Java里基本上所有的库都是同步阻塞的,很少见到异步无阻塞的。而且得益于J2EE,以及Java上的三大框架(SSH)洗脑,大部分Java程序员都已经习惯了基于线程,线性的完成一个业务逻辑,很难让他们接受一种将逻辑割裂的异步编程模型。

但是随着异步无阻塞这股风气起来,以及相关的coroutine语言Golang大力推广,人们越来越知道如何更好的榨干CPU性能(让CPU避免不必要的等待,减少上下文切换),阻塞的行为基本发生在I/O上,如果能有一个库能把所有的I/O行为都包装成异步阻塞的话,那么Quasar就会有用武之地,JVM上公认的是异步网络通信库是Netty,通过Netty基本解决了网络I/O问题,另外还有一个是文件I/O,而这个JDK7提供的NIO2就可以满足,通过AsynchronousFileChannel即可。剩下的就是如何将他们封装成更友好的API了。目前能达到生产级别的这种异步工具库,JVM上只有Vert.x3,封装了Netty4,封装了AsynchronousFileChannel,而且Vert.x官方也出了一个相对应的封装了Quasar的库vertx-sync。

本文参考:
Java Fork/Join 框架
次时代Java编程(一):Java里的协程
Java 多线程(5):Fork/Join 型线程池与 Work-Stealing 算法

个人微信公众号:

作者:jiankunking 出处:http://blog.csdn.net/jiankunking

Java Fork/Join与协程相关推荐

  1. java基于quasar实现协程池【后篇】

    java基于quasar实现协程池[前篇]:java基于quasar实现协程池_爪哇盘古的博客-CSDN博客 在上一个文章中讲述了通过仿照java自写线程池的方式改写成quasar协程池,功能可以说实 ...

  2. Java Fork/Join 框架

    转载自 http://www.importnew.com/27334.html Doug Lea 大神关于Java 7引入的他写的Fork/Join框架的论文. 响应式编程(Reactive Prog ...

  3. Java Fork / Join进行并行编程

    最近几年,计算机处理器领域发生了范式转变. 多年来,处理器制造商一直在提高时钟频率,因此开发人员享受到这样的事实,即他们的单线程软件执行得更快,而无需他们付出任何努力. 现在,处理器制造商青睐多核芯片 ...

  4. java基于quasar实现协程池

    业务场景:golang与swoole都拥抱了协程,在同任务并发数量下,协程可比线程多几倍.所以最近在查询java时了解java本身是没有协程的,但是某牛自行实现了协程,也就是本文的主角quasar(纤 ...

  5. Java Fork/Join框架

    原文 译序 Doug Lea 大神关于Java 7引入的他写的Fork/Join框架的论文. 响应式编程(Reactive Programming / RP)作为一种范式在整个业界正在逐步受到认可和落 ...

  6. java fork join原理_细说Fork/Join框架

    什么是Fork/Join框架? Fork/Join框架是JDK1.7提供的一个用于并行执行任务的框架,是一个把大任务分割成若干小任务,最终汇总每个小任务结果后得到大任务结果的框架.Fork就是把一个大 ...

  7. Kotlin学习笔记22 协程part2 join CoroutineScope 协程vs线程

    参考链接 示例来自bilibili Kotlin语言深入解析 张龙老师的视频 1 Job的join方法 import kotlinx.coroutines.* /*** Job的join方法* 它会挂 ...

  8. 20170702-变量说明,静态方法,类方法区别,断点调试,fork,yield协程,进程,动态添加属性等。。...

    概念: 并行:同时运行 并发:看似同时运行  json后任然中文的问题 import jsond = {"名字":"初恋这件小事"}new_d1 = json. ...

  9. JAVA Fork Join Demo 1

    2019独角兽企业重金招聘Python工程师标准>>> package com.famous.thread.util;import java.util.concurrent.Fork ...

最新文章

  1. 创建一个Android模拟器
  2. GP通过外部表装载数据时遇到ERROR:extra data after last expected column解决方法
  3. CComboBox 置空
  4. python 快速排序
  5. OO实现ALV TABLE 八:ALV的布局功能
  6. mysql 5.7源码包安装教程_MYSQL5.7源码包编译安装
  7. 如果你也会C#,那不妨了解下F#(6):面向对象编程之“类”
  8. 《Node应用程序构建——使用MongoDB和Backbone》一第 1 章 介绍与总览1.1 打造一个社交网络...
  9. mysql可重复读实验_Mysql可重复读测试
  10. cordova android项目自定义插件及使用(二)
  11. Atitit 模板引擎总结 目录 1. 模板引擎 1 2. 常见模板步骤 1 2.1. 1)定义模板字符串  1 2.2. 2)预编译模板  2 2.3. 渲染模板  2 3. 流程渲染 if el
  12. Ubuntu下 UltraEdit 破解/显色
  13. 一文了解新营销,数字经济时代如何以个人为中心重建品牌?
  14. elementui 下拉框回显_elementUI Cascader 级联选择器回显
  15. 一键发圈,一键转发到微信朋友圈或者微信好友
  16. 调节效应分析时简单斜率图或交互效应图出现负数截距?
  17. TCP/IP协议(2):各层网络设备
  18. 通过摄像机视频设备或者流媒体服务器SDK获取到数据转换成RTMP流实现网页手机微信播放
  19. Spark的Cache和Checkpoint区别和联系拾遗
  20. windows10环境下iceworks(飞冰)安装

热门文章

  1. 五个网络游戏植入商品营销的案例
  2. 机器学习第三章笔记——决策树
  3. 编译镜像(映像).img文件
  4. MAUI 入门教程系列(5.XAML及页面介绍)
  5. 微信云开发配置自有域名(短信跳转小程序)
  6. Android Tapjacking
  7. 斐波那契数列前20项及和
  8. 史上最全2019届秋招备战攻略
  9. SQL Server 数据库之视图
  10. python取模10^9+7_【Python爬虫】笨办法学python 习题1-10