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毫秒,为什么喃?搞不懂。。。求大神赐教