写在前面

我们都知道,在开发中有时候要想提高程序的效率,可以使用多线程去并行处理。而Java8的速度变快了,这个速度变快的原因中,很重要的一点就是Java8提供了并行方法,它使得我们的程序很容易就能切换成多线程,从而更好的利用CPU资源。

下面我们就来简单学习一下java8中得并行流与串行流。

并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。

Java8中将并行进行了优化,我们可以很容易的对数据进行并行操作。Stream API 可以声明性地通过parallel()与sequential()在并行流与顺序(串行)流之间进行切换

Fork/Join框架

在说并行流之前呢,我们首先来来接一下这个Fork/Join框架框架。

Java 7开始引入了一种新的Fork/Join线程池,它可以执行一种特殊的任务:把一个大任务拆成多个小任务并行执行。即在必要的情况下,将一个大的任务,进行拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运算的结果进行join汇总。

Fork/Join框架与传统线程池的区别

传统的线程池

我们就多线程来说吧,所谓的多线程就是把我们的任务分配到CPU不同的核上(也就是CPU不同的线程上)进行执行,我们以4核CPU为例。如果是传统线程的话,每个任务都有可能会阻塞,因为每个线程什么时候执行是由CPU时间片给他分配的执行权决定的,当这个时间片用完了以后,CPU会剥夺他的执行权,然后交给其他的线程去执行,这时就有可能出现阻塞的情况。即4核CPU我们可以看成4个线程,有可能其中俩线程中的一个任务阻塞造成后面的任务排队得不到执行,而另外两个没有阻塞的线程,则顺利执行完处于空闲状态了,这种有的线程在阻塞线程里的任务得不到执行,而别的不阻塞的线程空闲没有任务可以执行的状态,就造成了CPU资源的浪费,这样就会大大影响我们程序的执行效率。

Fork/Join框架

是把一个大任务拆分成若干个小任务,然后把这些小任务都压入到对应的线程中,也就是把这些小任务都压入到对应的CPU中(默认CPU有几核就有几个线程),然后形成一个个的线程队列。

Fork/Join任务的原理:判断一个任务是否足够小,如果是,直接计算,否则,就分拆成几个小任务分别计算。这个过程可以反复“裂变”成一系列小任务。

Fork/Join框架会将任务分发给线程池中的工作线程。Fork/Join框架的独特之处在于它使用“工作窃取”(work-stealing)算法。完成自己的工作而处于空闲的工作线程,能够从其他扔处于忙碌状态的工作线程中窃取等待执行的任务,每个工作线程都有自己的工作队列,这是使用双端队列(dequeue)来实现的。线程执行任务是从队列头部开始执行的,而处于空闲状态的线程,在窃取别的线程的任务的时候,是从被窃取线程的等待队列的队尾开始窃取的。这种情况下,就不会出现空闲的线程浪费CPU资源,因为一旦空闲便会去窃取任务执行。没有资源浪费,减少了线程的等待时间,所以效率就高,就提升了性能。

下面我们举个例子:如果要计算一个超大数组的和,最简单的做法是用一个循环在一个线程内完成。还有一种方法,可以把数组拆成两部分,分别计算,最后加起来就是最终结果,这样可以用两个线程并行执行,如果拆成两部分还是很大,我们还可以继续拆,用4个线程并行执行,这种即使用Fork/Join对大数据进行并行求和。

Fork/Join框架的使用

下面我们来写测试类演示一下:实现数的累加操作,比如说计算1到100亿的和。

我们要编写一个类继承RecursiveTask类,并重写compute()方法。

package com.cqq.java8.parallel;

import java.util.concurrent.RecursiveTask;

/**
* @Description:递归进行拆分
* @date 2021/3/14 7:55
*/
public class ForkJoinCalculate extends RecursiveTask<Long> { private Long start;
private Long end; public ForkJoinCalculate(Long start, Long end) {
this.start = start;
this.end = end;
} //临界值,当大于临界值的时候就一直拆分,小于临界值就不再进行拆分了
private static final long THREASHOLD = 100000000L; //重写compute方法
@Override
protected Long compute() { long length = end - start;
if(length <= THREASHOLD){//到临界值就不能再拆了
long sum = 0;
for (Long i = start; i <= end; i++) {
sum += i;
}
return sum;
}else{//不到临界值就进行拆分
long middle = (end + start);
ForkJoinCalculate left = new ForkJoinCalculate(start,middle);
//拆分子任务,同时压入线程队列
left.fork();
ForkJoinCalculate right = new ForkJoinCalculate(middle+1,end);
right.fork();
//拆完之后,合并,把fork()之后的结果得一个个合并,即累加总和
return left.join()+right.join(); }
}
}

测试方法

package com.cqq.java8;

import com.cqq.java8.parallel.ForkJoinCalculate;
import org.junit.Test; import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask; /**
* @Description:
* @date 2021/3/14 8:17
*/
public class TestForkJoin {
@Test
public void test01(){ //开始时间
Instant start = Instant.now();
//ForkJoin的执行需要一个ForkJoinPool的支持
ForkJoinPool pool = new ForkJoinPool(); ForkJoinTask<Long> task = new ForkJoinCalculate((long) 0,100000000L);
Long invoke = pool.invoke(task);
System.out.println(invoke);
//结束时间
Instant end = Instant.now();
//计算一下时间用 耗时多少
System.out.println(Duration.between(start,end).toMillis()); } //一个普通for循环即传统的单线程的测试类 与Fork/Join的执行结果做对比
@Test
public void test02(){ Instant start = Instant.now();
long sum = 0L; for (long i = 0; i < 100000000L; i++) {
sum += i;
}
System.out.println(sum);
Instant end = Instant.now();
System.out.println(Duration.between(start,end).toMillis()); }
}

测试结果

类加和 ForkJoin耗时 传统单线程耗时
1-1亿 521 85
1-10亿 241 363
1-100亿 1103 2431

从测试结果可以看出,当任务量不大时,传统单线程耗时短,任务达到一定量时ForkJoin的性能就很好了,因为在任务量不大时,拆分任务也要耗时,所以总的执行时间就比较长。说明,多线程也是要在合适的时候用才能提升性能。

Java8中的并行流

在Java 8中我们用的是parallel()方法,对并行流进行了优化。但是实际上底层还是用的Fork/Join框架。

    @Test
public void test03(){ Instant start = Instant.now(); //顺序流
long reduce = LongStream.rangeClosed(0, 100000000L)
.reduce(0, Long::sum); //使用parallel()并行流
OptionalLong reduce1 = LongStream.rangeClosed(0, 100000000L)
.parallel()//并行
.reduce(Long::sum); Instant end = Instant.now();
System.out.println(Duration.between(start,end).toMillis()); }

Java8 中不仅仅对代码进行了优化,而且效率也大大提升。

Java8的新特性--并行流与串行流的更多相关文章

  1. 【Java8新特性】关于并行流与串行流,你必须掌握这些!!

    写在前面 提到Java8,我们不得不说的就是Lambda表达式和Stream API.而在Java8中,对于并行流和串行流同样做了大量的优化.对于并行流和串行流的知识,也是在面试过程中,经常被问到的知 ...

  2. JDK8--07:并行流与串行流

    JDK8中,提供了并行流和串行流,使用parallel()和sequential()来处理,parallel()为并行流sequential()为串行流,两者可以相互转换,以最后一个为准 LongSt ...

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

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

  4. Java8新特性 - 并行流与串行流

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

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

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

  6. ForkJoin、并行流计算、串行流计算对比

    ForkJoin 什么是 ForkJoin ForkJoin 是一个把大任务拆分为多个小任务来分别计算的并行计算框架 ForkJoin 特点:工作窃取 这里面维护的都是双端队列,因此但其中一个线程完成 ...

  7. 深度分析:java8的新特性lambda和stream流,看完你学会了吗?

    1. lambda表达式 1.1 什么是lambda 以java为例,可以对一个java变量赋一个值,比如int a = 1,而对于一个方法,一块代码也是赋予给一个变量的,对于这块代码,或者说被赋给变 ...

  8. Java8 Stream新特性详解及实战

    Java8 Stream新特性详解及实战 背景介绍 在阅读Spring Boot源代码时,发现Java 8的新特性已经被广泛使用,如果再不学习Java8的新特性并灵活应用,你可能真的要out了.为此, ...

  9. java8的新特性以及用法简介

    1. 介绍 2 接口的默认方法 2 lambda表达式 2.1 函数式接口 2.2 方法与构造函数引用 2.3 访问局部变量 2.4 访问对象字段与静态变量 3. 内建函数式接口 3.1 Predic ...

随机推荐

  1. woj1002-Genesis woj1003-birthofnoah woj1004-noah's ark

    title: woj1002-Genesis date: 2020-03-05 categories: acm tags: [acm,woj] 输入输出考虑一下.easy #include <i ...

  2. C# 类 (8) - 抽象方法

    抽象 抽象方法 只能 定义在抽象类 里,并且抽象方法里没有具体的代码,像这种 为啥要定义一个空空如也的函数呢?这是为了用来约束 它的派生类 的行为, 这个例子,建立了一个数组,放了cat和dog,这两 ...

  3. .NET并发编程-数据结构不可变性

    本系列学习在.NET中的并发并行编程模式,实战技巧 内容目录 .NET不可变集合.NET并发集合函数式数据结构设计一个不可变类 作为程序员经常遇到产品上线后出现各种莫名其妙的问题,在我本地是好好的啊, ...

  4. React Hooks vs React Class vs React Function All In One

    React Hooks vs React Class vs React Function All In One React Component Types React Hooks Component ...

  5. cnblogs & 502 Bad Gateway

    cnblogs & 502 Bad Gateway 博客园 502 Bad Gateway 服务器发生了一些错误,请联系 contact@cnblogs.com 可以查看,不可以编辑 HTTP ...

  6. Open API collection

    Open API collection online API https://developer.github.com/v3/ https://developer.github.com/v4 http ...

  7. CSS overflow-anchor

    CSS overflow-anchor https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-anchor https://develop ...

  8. React & Dva & Actions & dispatch & effects

    React & Dva & Actions & dispatch & effects dispatch https://dvajs.com/guide/introduc ...

  9. 1月加密货币交易所访问量破3亿!NGK生态星空计划、NGK生态所带来双重利好!

    据最新数据显示,2021年一月份,加密货币交易所网站的访问量急剧上升.约有3.44亿访问者涌入了加密货币交易所,超过2020年12月的1.96亿访问者总数,创2018年1月以来新高. 加密货币交易所网 ...

  10. 新手如何通过SPC算力生态获得多重收益?

    DeFi市场在去年的一波又一波热潮之后,在今年余温有些褪去.而资本市场也将目光从DeFi市场中转移开来,他们将目光对准了新的市场,即算力市场.算力,其实从区块链技术在大范围普及以来,就是一个常见的话题 ...