分治思想
每个小任务最终都是多线程并发执行的(一个线程一个小任务),所以这个大任务执行过程不能有顺序要求,即:大任务可由小任务执行完后合并而成。
实战
ForkJoinPool应用
java.util.concurrent下的Future< V >就是多线程下的单个线程处理的任务,所以MyForkJoin就是个任务。
注意点: (Recursive递归的)
- RecursiveTask< V >有返回值
- RecursiveAction没有返回值
- 使用ForkJoin框架就得实现其中一种任务
package forkjoin;
import java.util.concurrent.RecursiveTask;
/**
* @Author: xiang
* @Date: 2021/2/17 14:04
*
* 创建ForkJoin框架
* RecursiveTask<V> => ForkJoinTask<V> => Future<V>
* 老祖宗是Future<V>,也就是任务
* MyForkJoin就是个任务类
*/
public class MyForkJoin extends RecursiveTask<Long> {
private static final long serialVersionUID = 4520854847015427243L;
private static final long THRESHOLD = 1000000L;//临界值 到达1000000L后不再fork
private long start;
private long end;
public MyForkJoin(long start, long end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
if(end - start < THRESHOLD){
long sum = 0;
for (long i=start;i<=end;++i){
sum += i;
}
return sum;
}else {
long mid = (end + start)/2;
//将大任务划分成两个小任务
MyForkJoin left = new MyForkJoin(start, mid);
MyForkJoin right = new MyForkJoin(mid + 1, end);
//小任务分支进行: 类似于两个线程.start()
left.fork();
right.fork();
//将任务结果合并
return left.join()+right.join();
}
}
}
- ForkJoin任务使用专门的ForkJoinPool去完成
- 使用invoke(task)去执行任务(execute()没有返回值)
package forkjoin;
import java.util.concurrent.ForkJoinPool;
/**
* @Author: xiang
* @Date: 2021/2/17 15:06
*/
public class TestForkJoin {
public static void main(String[] args) {
/**
* 使用ForkJoin框架多线程拆分大任务
* CPU利用率达100%
*/
//创建任务
MyForkJoin myForkJoin = new MyForkJoin(0, 10000000000L);
//创建线程池
ForkJoinPool forkJoinPool = new ForkJoinPool(10);
//将任务放入线程池中
long sum = forkJoinPool.invoke(myForkJoin);
System.out.println(sum);
}
}
回顾Callable< V >
package forkjoin;
import java.util.concurrent.Callable;
/**
* @Author: xiang
* @Date: 2021/2/17 15:15
*/
public class MyThread implements Callable<Long>{
private long start;
private long end;
private static final long THRESHOLD = 1000000L;
public MyThread(long start, long end) {
this.start = start;
this.end = end;
}
@Override
public Long call() throws Exception {
long sum = 0;
for (long i=start;i<=end;++i){
sum += i;
}
return sum;
}
}
注意,是 任务.get() 获得返回值
package forkjoin;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* @Author: xiang
* @Date: 2021/2/17 15:06
*/
public class TestForkJoin {
public static void main(String[] args) throws ExecutionException, InterruptedException {
/**
* 使用单线程
* CPU利用率70%
*/
//创建任务
FutureTask<Long> task = new FutureTask<>(new MyThread(0, 10000000000L));
//将任务也给予线程
Thread thread = new Thread(task);
//开启线程
thread.start();
long sum1 = task.get();
System.out.println(sum1);
}
}
最强还是并行流parallelStream
/**
* jdk8 新特性
* 使用stream
* CPU100% 速度也最快!!!
*/
long sum2 = LongStream.rangeClosed(0,10000000000L)
.parallel()
.sum();
System.out.println(sum2);