ForkJoin与并行流比较

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<Long> 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<Long>{
		//常量是不能更改的,且所有实例共享同一個常量,所以用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毫秒,为什么喃?搞不懂。。。求大神赐教

猜你喜欢

转载自my.oschina.net/u/3049601/blog/1625498