ForkJoinPool及并行流解析
parallelStream原理。
parallelStream是并行流,依赖jdk1.7出现的Fork/Join框架。
Fork/Join框架的核心是工作窃取(work-stealing)算法。那么什么是工作窃取算法呢?假如我们有一个比较大的任务,我们可以把这个任务分割为若干互不依赖的子任务,为了减少线程间的竞争,于是把这些子任务分别放到不同的队列里,并为每个队列创建一个单独的线程来执行队列里的任务,线程和队列一一对应,比如A线程负责处理A队列里的任务。但是有的线程会先把自己队列里的任务干完,而其他线程对应的队列里还有任务等待处理。干完活的线程与其等着,不如去帮其他线程干活,于是它就去其他线程的队列里窃取一个任务来执行。而在这时它们会访问同一个队列,所以为了减少窃取任务线程和被窃取任务线程之间的竞争,通常会使用双端队列,被窃取任务线程永远从双端队列的头部拿任务执行,而窃取任务的线程永远从双端队列的尾部拿任务执行。
ForkJoinPool是一个运行ForkJoinTask的线程池,同ThreadPoolExecutor一样,也继承了AbstractExecutorService。ForkJoinPool的每个工作线程都维护着一个工作队列,这是一个双端队列Deque,里面存放着任务ForkJoinTask。每个工作线程在运行过程中,产生的新任务会放到工作队列的队尾。工作线程在处理自己工作队列任务时,每次是从队尾取任务。当自己的工作队列清空后,会尝试去窃取其他工作队列的任务,且是从队首窃取。
并行流处理过程中,用的ForkJoinTask是CountedCompleter的几个子类,如forEach()操作对应的是ForEachTask,forEachOrdered()操作对应的是ForEachOrderedTask,reduce()操作对应的是ReduceTask。
以Lists.newArrayList(1, 2, 3).parallelStream().forEach(System.out::println);为例,用的ForkJoinPool实例是
跟到ForEachTask的compute()方法,ForEachTask 第283行,AbstractTask.suggestTargetSize(sizeEstimate);
AbstractTask的suggestTargetSize()方法实现是:
- public static long suggestTargetSize(long sizeEstimate) {
- long est = sizeEstimate / LEAF_TARGET;
- return est > 0L ? est : 1L;
- }
其中,LEAF_TARGET值定义是
static final int LEAF_TARGET = ForkJoinPool.getCommonPoolParallelism() << 2;
这里就调用了ForkJoinPool的getCommonPoolParallelism()静态方法。ForkJoinPool有一个static块,里面调用ForkJoinPool的makeCommonPool()静态方法给静态的ForkJoinPool实例common赋值。makeCommonPool()方法内部调用了ForkJoinPool的private的构造方法,其中第一个参数并行度的值是CPU核心数-1。取CPU核心数的代码是Runtime.getRuntime().availableProcessors()。
- if (parallelism < 0 &&
- (parallelism = Runtime.getRuntime().availableProcessors() - 1) <= 0)
- parallelism = 1;
- if (parallelism > MAX_CAP)
- parallelism = MAX_CAP;
我们如果想用ForkJoinPool实现自己的业务,则需要继承ForkJoinTask。更简单点,只需继承ForkJoinTask的子类RecursiveTask或者RecursiveAction,重写compute()方法即可。
案例见:https://blog.csdn.net/niyuelin1990/article/details/78658251
ForkJoinPool及并行流解析的更多相关文章
- java8学习之收集器枚举特性深度解析与并行流原理
首先先来找出上一次[http://www.cnblogs.com/webor2006/p/8353314.html]在最后举的那个并行流报错的问题,如下: 在来查找出上面异常的原因之前,当然得要一点点 ...
- Fork/Join框架与Java8 Stream API 之并行流的速度比较
Fork/Join 框架有特定的ExecutorService和线程池构成.ExecutorService可以运行任务,并且这个任务会被分解成较小的任务,它们从线程池中被fork(被不同的线程执行)出 ...
- Java8新特性 并行流与串行流 Fork Join
并行流就是把一个内容分成多个数据块,并用不同的线程分 别处理每个数据块的流. Java 8 中将并行进行了优化,我们可以很容易的对数据进行并 行操作. Stream API 可以声明性地通过 para ...
- JAVA8给我带了什么——并行流和接口新功能
流,确定是笔者内心很向往的天堂,有他之后JAVA在处理数据就变更加的灵动.加上lambda表达不喜欢都不行.JAVA8也为流在提供另一个功能——并行流.即是有并行流,那么是不是也有顺序流.没有错.我前 ...
- jdk8--stream并行流
stream的并行流要理解一个框架如下: 单线程,多线程和并行流对比 package com.atguigu.java8; import java.util.concurrent.ForkJoinPo ...
- list.stream().parallel() 并行流
https://blog.csdn.net/u011001723/article/details/52794455/ : parallel()其实就是一个并行执行的流.它通过默认的ForkJoin ...
- java8新特性——并行流与顺序流
在我们开发过程中,我们都知道想要提高程序效率,我们可以启用多线程去并行处理,而java8中对数据处理也提供了它得并行方法,今天就来简单学习一下java8中得并行流与顺序流. 并行流就是把一个内容分成多 ...
- Stream的顺序流与并行流
/** * @auther hhh * @date 2019/1/2 22:52 * @description */ public class StreamAPI2 { /** * 流的特性:支持并行 ...
- 三、并行流与串行流 Fork/Join框架
一.并行流概念: 并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流. java8中将并行进行了优化,我们可以很容易的对数据进行并行操作.Stream API可以声明性的通过pa ...
随机推荐
- adb将Apk内置到系统中(system/priv-app)
https://blog.csdn.net/starhosea/article/details/78697007 so文件的处理是目前遇到过的问题.文章中解释了. 正文: 有时候我们在Android ...
- HDU 1087 Super Jumping! Jumping! Jumping! (动态规划、最大上升子序列和)
Super Jumping! Jumping! Jumping! Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 ...
- mysql查看锁查看
关键词:mysql锁争用,mysql锁查看 --------------------- 作者:边城cn 来源:CSDN 原文:https://blog.csdn.net/miyatang/articl ...
- [转帖]C#中字典集合HashTable、Dictionary、ConcurrentDictionary三者区别
C#中字典集合HashTable.Dictionary.ConcurrentDictionary三者区别 https://blog.csdn.net/yinghuolsx/article/detail ...
- java中易错点
1.A instanceof B{这是没有好好利用java多态的表现} java中的二元操作符,测试A对象是否是B类的实例: 返回值:boolean类型 2.“==”与 “equals”的区别: = ...
- jira:恢复数据:AO_187CCC_SIDEBAR_LINK
JIRA 恢复数据时报错 ,关键词是找不到 AO_187CCC_SIDEBAR_LINK. 经网上查为 mysql connect jar 包 的版本过高所致. 降低版本后,成功导入数据.
- Luogu P1631 序列合并
题目 开一个堆,先把所有\(a[i]+b[1]\)压进优先队列. 然后每次把最小的取出来,把对应的\(a[i]\)的下一个\(b[j]\)拿出来加进去. #include<bits/stdc++ ...
- Android引用多媒体
res目录下,创建raw目录(Android会自动识别这个目录),如果自己创建的目录,可能无效底下的mp3格式,mp4格式的文件名必须小写. 引用方式: mediaPlayer = MediaPlay ...
- python3爬取动态网站图片
思路: 1.图片放在<image>XXX</image>标签中 2.利用fiddler抓包获取存放图片信息的js文件url 3.利用requests库获取html内容,然后获取 ...
- selenium与页面交互之二:webelement类的属性
webelement类的属性如下: element.size() 获取元素的大小 element.tag_name() 获取元素的HTML标签名称 element.text() 获取元素的文本 ...