1.分支合并-forkjoin
ForkJoin的框架的基本思想是分而治之。什么是分而治之?分而治之就是将一个复杂的计算,按照设定的阈值进行分解成多个计算,然后将各个计算结果进行汇总。相应的ForkJoin将复杂的计算当做一个任务。而分解的多个计算则是当做一个子任务。
Fork/Join与传统线程池的区别!
Fork/Join采用“工作窃取模式”,当执行新的任务时他可以将其拆分成更小的任务执行,并将小任务加到线程队列中,然后再从一个随即线程中偷一个并把它加入自己的队列中。
就比如两个CPU上有不同的任务,这时候A已经执行完,B还有任务等待执行,这时候A就会将B队尾的任务偷过来,加入自己的队列中,对于传统的线程,ForkJoin更有效的利用的CPU资源!
测试forkjoin
package com.coding.forkjoin;
import java.util.concurrent.RecursiveTask;
// 求和
public class ForkJoinWork extends RecursiveTask<Long> {
private Long start;
private Long end;
private static final Long tempLong = 10000L; // 临界值
public ForkJoinWork(Long start, Long end) {
this.start = start;
this.end = end;
}
// 计算方法
@Override
protected Long compute() {
// 临界值判断
if ((end-start)<=tempLong){
Long sum = 0L;
for (Long i = start; i <= end ; i++) {
sum += i;
}
return sum;
}else { // 第二种方式
long middle = (end + start) / 2;
ForkJoinWork right = new ForkJoinWork(start,middle);
right.fork(); // 压入线程队列
ForkJoinWork left = new ForkJoinWork(middle+1,end);
left.fork(); // 压入线程队列
// 获得结果 join 会阻塞等待结果
return right.join() + left.join();
}
}
}
package demo.forkjoin;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.LongStream;
public class MyTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
test1();
test2();
test3();
}
// 普通的
private static void test3() {
Long sum = 0L;
long start = System.currentTimeMillis();
for (Long i = 0L; i <= 1000000000L ; i++) {
sum += i;
}
long end = System.currentTimeMillis();
System.out.println("times:"+(end-start)+" r=>"+sum);
}
// forkjoin
private static void test2() throws ExecutionException, InterruptedException {
long start = System.currentTimeMillis();
ForkJoinPool forkJoinPool = new ForkJoinPool();
ForkJoinWork forkJoinWork = new ForkJoinWork(0L, 1000000000L);
ForkJoinTask<Long> submit = forkJoinPool.submit(forkJoinWork);
Long sum = submit.get();
long end = System.currentTimeMillis();
System.out.println("times:"+(end-start)+" r=>"+sum);
}
// 并行流计算
private static void test1() {
long start = System.currentTimeMillis();
// 流计算
long sum = LongStream.rangeClosed(0L, 1000000000L).parallel().reduce(0, Long::sum);
long end = System.currentTimeMillis();
System.out.println("times:"+(end-start)+" r=>"+sum);
}
}
这里把代码给大家,大家可以自行测试,我电脑可能是配置问题,导致普通的算的比较快
注:
使用ForkJoin将相同的计算任务通过多线程的进行执行。从而能提高数据的计算速度。但是我们需要注意:
-
使用这种多线程带来的数据共享问题,在处理结果的合并的时候如果涉及到数据共享的问题,我们尽可能使用JDK为我们提供的并发容器。
-
在使用JVM的时候我们要考虑OOM的问题,如果我们的任务处理时间非常耗时,并且处理的数据非常大的时候。会造成OOM。
-
ForkJoin也是通过多线程的方式进行处理任务。那么我们不得不考虑是否应该使用ForkJoin。因为当数据量不是特别大的时候,我们没有必要使用ForkJoin。因为多线程会涉及到上下文的切换。所以数据量不大的时候使用串行比使用多线程快。
来源:CSDN
作者:去吧!小火龙
链接:https://blog.csdn.net/weixin_40307709/article/details/104716467