JUC:ForkJoinPool类的理解与应用、CompletableFuture类的理解与应用
文章目录
ForkJoinPool类 JDK 1.7
ForkJoin 并发执行任务,提高效率,在大数据量表现显著。最适合的是计算密集型的任务。
ForkJoin工作原理
- 是将大量的数据分成多个子任务处理,然后合并。
ForkJoin特点
- 工作窃取:该线程的任务执行完之后,就会去窃取其他线程没有执行完的任务,把任务拿到自己这里来执行,提高效率。
- 用的双端队列
java.util.concurrent.ForkJoinPool
类继承Executor。
常用方法
public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task)
提交一个ForkJoinTask来执行。
ForkJoinTask是一个抽象类方法,如果要使用ForkJoinPool去执行代码,就得继承ForkJoinTask的子抽象类去实现,然后使用ForkJoinPool的submmit方法去使用
ForkJoinTask<V> 抽象类
public final ForkJoinTask <V> fork()
把拆分任务压入到线程中public final V join()
返回计算结果
RecursiveAction 抽象类
protected abstract void compute()
这个任务执行的主要计算。
RecursiveTask<V> 抽象类
protected abstract V compute()
这个任务执行的主要计算。
LongStream 接口
-
static LongStream range(long startInclusive,long endExclusive)
返回从startInclusive(含)至 endExclusive通过增量步骤 1的最终结果。 [start,end) -
static LongStream range(long startInclusive,long endExclusive)
返回从startInclusive至 endExclusive(含)通过增量步骤 1的最终结果。 (start,end] -
LongStream parallel()
使其为并行流 -
long reduce(long identity, LongBinaryOperator op)
合并流产生的元素,并产生单个值返回。
案例 使用ForkJoin,并行Stream计算大数据的和
Recursive 递归
parallel 平行
ForkJoinDemon.java
public class ForkJoinDemon extends RecursiveTask<Long> { private long start; private long end; private final long temp = 10000L; // 规定一个临界值 public ForkJoinDemon(long start, long end) { this.start = start; this.end = end; } // 递归合并 @Override protected Long compute() { // 如果计算的两个值在临界值以内,就直接使用for循环计算 if((end - start) < temp){ long sum = 0L; for (long i = start; i <= end; i++) { sum += i; } return sum; }else { // 计算中间值,将其分为两个线程两个对象去进行计算,在new的新对象中, // 也会去判断是否在临界值以内,否则还会继续new一个新对象,进入新线程中计算 long middle = (end + start)/2; ForkJoinDemon task1 = new ForkJoinDemon(start, middle); task1.fork(); // 把拆分任务压入到线程中 ForkJoinDemon task2 = new ForkJoinDemon(middle + 1, end); task2.fork(); return task1.join()+task2.join(); // 将两个任务的返回值,合并在一起 } } }
ForkJoinTest.java
public class ForkJoinTest { public static void main(String[] args) throws ExecutionException, InterruptedException { // test01(); // 结果:500000000500000000 时间:723 test02(); // 结果:500000000500000000 时间:641 // test03(); // 结果:500000000500000000 时间:467 } // 普通方法for循环计算 public static void test01(){ long start = System.currentTimeMillis(); long sum = 0L; for (int i = 1; i <= 10_0000_0000L; i++) { sum += i; } long end = System.currentTimeMillis(); System.out.println("结果:" + sum + " 时间:" + (end-start)); } // 使用ForkJoin 并行计算 public static void test02() throws ExecutionException, InterruptedException { long start = System.currentTimeMillis(); long sum = 0L; ForkJoinPool joinPool = new ForkJoinPool(); ForkJoinDemon joinDemon = new ForkJoinDemon(0L, 10_0000_0000L); ForkJoinTask<Long> submit = joinPool.submit(joinDemon); sum = submit.get(); long end = System.currentTimeMillis(); System.out.println("结果:" + sum + " 时间:" + (end-start)); } // 使用Stream流 并行计算 public static void test03(){ long start = System.currentTimeMillis(); // 设置计算范围,增1计算,使用并行,将并行线程的值合并成一个值,返回 long sum = LongStream.rangeClosed(0, 10_0000_0000L).parallel().reduce(0, (a, b) -> a + b); long end = System.currentTimeMillis(); System.out.println("结果:" + sum + " 时间:" + (end-start)); } }
CompletableFuture<T>类 异步回调 JDK1.8
java.util.concurrent.CompletableFuture<T>
类,异步回调类。如同前端的Ajax。如在主线程new了该类,该类会创建一个新的线程去执行任务,并且主线程和该新线程互不影响。可同时进行。
构造方法
public CompletableFuture()
创建一个新的不完整的CompletableFuture
常用方法
public static CompletableFuture<Void> runAsync(Runnable runnable)
异步完成任务,并没有返回值public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
异步完成任务,有返回值public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action)
当成功完成异步任务的回调函数。public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn)
捕获异常,并由返回值。
public class CompletableFutureTest { public static void main(String[] args) throws ExecutionException, InterruptedException { // 没有返回值 CompletableFuture<Void> runAsync = CompletableFuture.runAsync(() -> System.out.println("已执行runAsync 200")); runAsync.get(); // 获取结果值,如果一直执行不完,该方法就会被阻塞,一直等待去get // 有返回值 CompletableFuture<Integer> supplyAsync = CompletableFuture.supplyAsync(() -> { // System.out.println(19/0); return 200; }); //System.out.println(supplyAsync.get()); // 当成功完成 Integer info = supplyAsync.whenComplete((t, e) -> { System.out.println(t); // 获得成功执行完成的返回值,如果执行出错为null System.out.println(e); // 如果执行不成功,获取异常信息,如果没有异常为null }).exceptionally((e) -> { // 如果没有异常不执行 e.getMessage(); // 将执行失败的异常信息获取出来 return 404; // 有返回值 }).get(); System.out.println(info); } } /* 输出: 已执行runAsync 200 200 null 200*/