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及并行流解析的更多相关文章

  1. java8学习之收集器枚举特性深度解析与并行流原理

    首先先来找出上一次[http://www.cnblogs.com/webor2006/p/8353314.html]在最后举的那个并行流报错的问题,如下: 在来查找出上面异常的原因之前,当然得要一点点 ...

  2. Fork/Join框架与Java8 Stream API 之并行流的速度比较

    Fork/Join 框架有特定的ExecutorService和线程池构成.ExecutorService可以运行任务,并且这个任务会被分解成较小的任务,它们从线程池中被fork(被不同的线程执行)出 ...

  3. Java8新特性 并行流与串行流 Fork Join

    并行流就是把一个内容分成多个数据块,并用不同的线程分 别处理每个数据块的流. Java 8 中将并行进行了优化,我们可以很容易的对数据进行并 行操作. Stream API 可以声明性地通过 para ...

  4. JAVA8给我带了什么——并行流和接口新功能

    流,确定是笔者内心很向往的天堂,有他之后JAVA在处理数据就变更加的灵动.加上lambda表达不喜欢都不行.JAVA8也为流在提供另一个功能——并行流.即是有并行流,那么是不是也有顺序流.没有错.我前 ...

  5. jdk8--stream并行流

    stream的并行流要理解一个框架如下: 单线程,多线程和并行流对比 package com.atguigu.java8; import java.util.concurrent.ForkJoinPo ...

  6. list.stream().parallel() 并行流

    https://blog.csdn.net/u011001723/article/details/52794455/  :  parallel()其实就是一个并行执行的流.它通过默认的ForkJoin ...

  7. java8新特性——并行流与顺序流

    在我们开发过程中,我们都知道想要提高程序效率,我们可以启用多线程去并行处理,而java8中对数据处理也提供了它得并行方法,今天就来简单学习一下java8中得并行流与顺序流. 并行流就是把一个内容分成多 ...

  8. Stream的顺序流与并行流

    /** * @auther hhh * @date 2019/1/2 22:52 * @description */ public class StreamAPI2 { /** * 流的特性:支持并行 ...

  9. 三、并行流与串行流 Fork/Join框架

    一.并行流概念: 并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流. java8中将并行进行了优化,我们可以很容易的对数据进行并行操作.Stream API可以声明性的通过pa ...

随机推荐

  1. 深入理解java:4.3. 框架编程之MyBatis原理深入解析

    1 引言 本文主要讲解JDBC怎么演变到Mybatis的渐变过程,重点讲解了为什么要将JDBC封装成Mybaits这样一个持久层框架.再而论述Mybatis作为一个数据持久层框架本身有待改进之处. 2 ...

  2. 7大python 深度学习框架的描述及优缺点绍

    Theano https://github.com/Theano/Theano 描述: Theano 是一个python库, 允许你定义, 优化并且有效地评估涉及到多维数组的数学表达式. 它与GPUs ...

  3. springBoot2.0 Yaml值获取

    1. pom.xml添加如下依赖 <dependency> <groupId>org.springframework.boot</groupId> <arti ...

  4. hadoop-组件

    hadoop1.x 和 hadoop2.x 区别 HDFS 分布式文件存储系统 优点   缺点 MapReduce 分布式计算 详见我的博客 mapreduce YARN 计算资源管理器 主要了解两个 ...

  5. 自己动手实现一个html2canvas

    前言 昨天写了新手引导动画的4种实现方式,里面用到了 html2canvas 于是就顺便了解了一下实现思路. 大概就是 利用 svg 的 foreignObject 标签, 嵌入 dom, 最后再利用 ...

  6. APT高持续渗透攻击-后门篇

    APT是指高级持续性威胁, 利用先进的攻击手段对特定目标进行长期持续性网络攻击的攻击形式,APT攻击的原理相对于其他攻击形式更为高级和先进,其高级性主要体现在APT在发动攻击之前需要对攻击对象的业务流 ...

  7. mysql复制表结构,复制表数据

    MYSQL 复制表 show create table table_name:查看表的建表语句.该语句包含了原数据表的结构,索引等. 使用 SHOW CREATE TABLE 命令获取创建数据表(CR ...

  8. api接口统一封装

    具体的接口api模块,例如authorization.js import axios from '../axiosWrapper' let prefix = process.env.API_ROOT ...

  9. 原型链—— javascript

    目录 js面向对象编程 js原型链 共享方法 原型继承 class继承 js面向对象编程 js面向对象编程不同于 java 的类和对象 JavaScript 不区分类和实例的概念,而是通过原型(pro ...

  10. shell编程注意点

    1.标准输入输出转存不能随便用,例如: echo "export PATH=/home/huangmr/jdk/bin:\$PATH" >> /home/huangmr ...