ForkJoin与并行流比较

2018-03-01 11:24:44来源:oschina作者:特拉仔人点击

分享
Fork-Join

该框架是JDK1.7推出来的,用于将大任务分解成N多个小任务,使用的要点为:


1.创建任务类,该类必须继承ForkJoinTask或者ForkJoinTask的子类,比如RecursiveTask(带返回值),RecursiveAction(不带返回值),其中的核心实现方法需要对任务做分解,可以参考下面例子的compute方法中对任务的分解


2.创建线程池ForkJoinPool


3.创建任务


4.将任务提交给线程池


关于该框架的详细可以参考:Fork/Join框架详解


并行流

JDK1.8带来了强大的Lambda和Stream流,其中流还有串行和并行流,前面的文章都是讲的串行流,比如:


Arrays.asList(1,2,3,4).forEach(System.out::println);

输出结果:



再来一个它的并行流写法:


Arrays.asList(1,2,3,4).parallelStream().forEach(System.out::println);

输出结果:



从结果很容易看出并行流输出是无序的,所以在使用并行流的时候要特别注意需求是不是可以不关心顺序。


为什么要用并行流,当然是充分利用CPU多核的资源,提高数据的处理能力,加快响应速度。

举例
package com.jv.java8.stream;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.stream.LongStream;
import org.junit.Test;
public class ForkJoinCompareStream {
//fork join 框架
@Test
public void test1() {
Instant start = Instant.now();
//使用默认构造函数创建池,你也可以使用带参的,会在博客中做讲解
ForkJoinPool pool = new ForkJoinPool();
//创建任务
MyTask mt = new MyTask(0L,1000000000L);//耗时:10200毫秒
//将任务放入池中
ForkJoinTask t = pool.submit(mt);
try {
System.out.println(t.get());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Instant end = Instant.now();
System.out.println(Duration.between(start, end).toMillis());
}

//Stream 并行流
@Test
public void test2() {
Instant start = Instant.now();
//LongStream.rangeClosed(0,10)会产生0到10的整数,step为1
Long sum = LongStream.rangeClosed(0,1000000000L).parallel().sum();//耗时:226毫秒
System.out.println(sum);
Instant end = Instant.now();
System.out.println(Duration.between(start, end).toMillis());
}

class MyTask extends RecursiveTask{
//常量是不能更改的,且所有实例共享同一個常量,所以用final來修饰
//当计算任务的开始结束值<=THRESHOLD的时候,就不再fork任务了
private final static long THRESHOLD=10000;
Long start = 0L;
Long end = 0L;

public MyTask() {}

public MyTask(Long start,Long end) {
this.start = start;
this.end = end;
}

@Override
protected Long compute() {
Long t = end - start;
Long sum = 0L;
if(t<=THRESHOLD) {
for(;start<=end;start++) {
sum += start;
}
}else {
Long m = (end + start)/2;
MyTask left = new MyTask(start,m);
MyTask right = new MyTask(m+1,end);
left.fork();
right.fork();
sum = left.join()+right.join();
}
return sum;
}
}

@Test
public void test3() {
Arrays.asList(1,2,3,4).forEach(System.out::println);
}
}

在上面的例子中看到使用Fork-Join框架执行的时间为10200毫秒,而使用并行流居然只有226毫秒,为什么喃?搞不懂。。。求大神赐教

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台