Java 7开始引入了一种新的Fork/Join线程池,它可以执行一种特殊的任务:把一个大任务拆成多个小任务并行执行。
ForkJoin的一个特点:工作窃取
比如:一个任务分成了两个线程执行,第一个线程执行完成,而第二个还没完成,第一个就会窃取第二个线程的任务执行,以提高效率。
图片.png
如何使用ForkJoin
1、通过ForkJoinPool的execute()方法
图片.png
2、创建ForkJoinTask:
图片.png
因为我们的例子是循环计算值,所以需要有返回值的。
示例:
package com.company.forkjoin;
import java.util.concurrent.RecursiveTask;
/**
* 求和计算。计算10亿个数据之和
* 1、直接循环10亿次
* 2、用ForkJoin
* 3、用stream并行流
* //ForkJoin的使用方法:
* //1、通过ForkJoinPool来执行
* //2、计算任务:ForkJoinPool.execute(ForkJoinTask task)
* //3、创建ForkJoinTask(RecursiveTask是ForkJoinTask的子类)
*/
public class TestForkJoin extends RecursiveTask {
private Long start;
private Long end;
//临界值
private Long temp = 10000L;
public TestForkJoin(Long start, Long end) {
this.start = start;
this.end = end;
}
//计算方法
@Override
protected Long compute() {
if ((end-start)
Long sum = 0L;
for (Long i = start; i <= end; i++) {
sum += i;
}
return sum;
}else{ //forkjoin
//将一个大任务拆成两个任务
long middle = (start+end)/2;
TestForkJoin task1 = new TestForkJoin(start, middle);
task1.fork();//将任务task1压入线程队列
TestForkJoin task2 = new TestForkJoin(middle + 1, end);
task2.fork();//将任务task2压入线程队列
//获取结果
long sum = task1.join() + task2.join();
return sum;
}
}
}
测试三种方计算任务:
package com.company.forkjoin;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.LongStream;
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//test1();//sum=500000000500000000,时间:14453
//test2();//sum=500000000500000000,时间:12515
//test3();//sum=500000000500000000,时间:907
}
//直接for循环
public static void test1(){
Long sum = 0L;
long start = System.currentTimeMillis();
for (Long i = 0L; i <= 10_0000_0000; i++) {
sum += i;
}
long end = System.currentTimeMillis();
System.out.println("sum="+sum+",时间:"+(end-start));
}
//使用ForkJoin
public static void test2() throws ExecutionException, InterruptedException {
long start = System.currentTimeMillis();
ForkJoinPool forkJoinPool = new ForkJoinPool();//创建ForkJoinPool
TestForkJoin forkJoinTask = new TestForkJoin(0L, 10_0000_0000L); //创建Task
//forkJoinPool.execute(forkJoinTask);//执行任务没有返回结果
ForkJoinTask submit = forkJoinPool.submit(forkJoinTask);//提交任务
Long sum = submit.get(); //获取值
long end = System.currentTimeMillis();
System.out.println("sum="+sum+",时间:"+(end-start));
}
//Stream并行流
public static void test3(){
long start = System.currentTimeMillis();
long sum = LongStream.rangeClosed(0L, 10_0000_0000).parallel().reduce(0, Long::sum);
long end = System.currentTimeMillis();
System.out.println("sum="+sum+",时间:"+(end-start));
}
}