-
ForkJoin把一个大任务拆分成不同的小任务,并使用ForkJoinPool中的线程池分别执行不同的任务。
ForkJoin中有一个任务窃取的概率,即一个线程执行完任务后,可以去执行其他线程中的任务。
ForkJoinPool中维护了一个双端队列。
可以指定任务的拆分规则。
如果任务拆分不当可能会降低效率。
-
Stream并行流,并行操作,效率最高
-
示例计算一个大数的累计,比较普通循环、ForkJoin、并行流的效率
//ForkJoinDemo 类 //RecursiveTask 递归执行有返回值 //RecursiveAction 递归执行 没有返回值 public class ForkJoinDemo extends RecursiveAction<Long> { private Long start; private Long end; private final Long tmp = 10000L; public ForkJoinDemo(Long start,Long end){ this.start = start; this.end = end; } //类似递归 @Override protected Long compute() { Long sub = end - start; if(sub < tmp){ //如果小于临界值 使用普通方式计算 Long sum = 0L; for (long i = start; i <= end; i++) { sum += i; } return sum; }else{ //分成两个子任务 Long midd = (end + start) / 2; ForkJoinDemo task1 = new ForkJoinDemo(start,midd); task1.fork(); ForkJoinDemo task2 = new ForkJoinDemo(midd+1,end); return task2.compute() + task1.join(); } } } //测试类 public class ForkJoinTest { private static final long start = 0L; private static final long end = 1_000_000_000L; public static void main(String[] args) { test1(); test2(); test3(); } /** * 普通方法 * 循环加 */ public static void test1(){ Long startTime = System.currentTimeMillis(); Long sum = 0L; for (long i = start; i <= end; i++) { sum += i; } Long endTime = System.currentTimeMillis(); System.out.println("test1计算结果:"+ sum +",耗时"+ (endTime-startTime) + "毫秒"); } /** * ForkJoin 分支合并 */ public static void test2(){ Long startTime = System.currentTimeMillis(); Long sum = 0L; ForkJoinPool forkJoinPool = new ForkJoinPool(); ForkJoinTask<Long> task = new ForkJoinDemo(start,end); ForkJoinTask<Long> submit = forkJoinPool.submit(task); try { sum = submit.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } Long endTime = System.currentTimeMillis(); System.out.println("test2计算结果:"+ sum +",耗时"+ (endTime-startTime) + "毫秒"); } /** * stream 并行流 */ public static void test3(){ Long startTime = System.currentTimeMillis(); Long sum = 0L; sum = LongStream.rangeClosed(start,end).parallel().reduce(0,Long::sum); Long endTime = System.currentTimeMillis(); System.out.println("test3计算结果:"+ sum +",耗时"+ (endTime-startTime) + "毫秒"); } }
结果
普通循环累加最耗时
ForkJoin其次,可以通过改变拆分策略来提升效率
stream并行流效率最高