JDK1.8新特性介绍(一)——CompletableFuture应用与源码解析

1、异步任务创建

在CompletableFuture中提供了四个静态方法用于创建异步任务
runAsync(Runnable runnable)
runAsync(Runnable runnable,Executor executor)
supplyAsync(Supplie<U> supplier)
supplyAsync(Supplier<U> supplier,Executor executor)

1.1 runAsync()应用与源码解析

在这里插入图片描述
根据源码可知,runAsync()分为一个参数和两个参数,并且其内部都会调用asyncRunStage()。
在这里插入图片描述
在该方法内部会创建异步任务,并把任务放入线程池中。并且runAsync()是没有返回值的。
根据源码可知,当传入Executor会使用指定线程池执行,如果没有传入则使用默认ForkJoinPool.commonPool()执行,值得注意的是,commonPool中都是守护线程,主线程执行完,子线程也就over了。因此建议当任务非常耗时,使用自定义线程池。

//未设置Executor
public class RunAsyncDemo {
   
    public static void main(String[] args) {
   
        CompletableFuture<Void> child_run = CompletableFuture.runAsync(() -> {
   
            try {
   
                Thread.sleep(1000);
                System.out.println("child run");
            } catch (InterruptedException e) {
   
                e.printStackTrace();
            }
        });
        System.out.println("main end");
    }
}

根据结果可以看到,子线程没有来得及打印,主线程就结束了。

//设置自定义线程池
public class RunAsyncDemo2 {
   

    public static void main(String[] args) {
   
        ExecutorService executorService = Executors.newFixedThreadPool(100);
        CompletableFuture<Void> child_run = CompletableFuture.runAsync(() -> {
   
            try {
   
                Thread.sleep(1000);
            } catch (InterruptedException e) {
   
                e.printStackTrace();
            }
            System.out.println("child run");
        }, executorService);
        System.out.println("main end");
    }
}

根据结果可以看到,就算主线程执行完,但并不会关闭子线程,子线程结果一样可以输出。

1.2 supplyAsync()应用与源码解析

在这里插入图片描述
根据源码可知,supplyAsync()分为一个参数和两个参数,并且其内部都会调用asyncSupplyStage()。
在这里插入图片描述
现在可知,其实supplyAsync()与runAsync()内部原理类似,但supplyAsync()有返回值。

public class supplyAsyncDemo {
   
    public static void main(String[] args) throws ExecutionException, InterruptedException {
   
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
   
            try {
   
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
   
                e.printStackTrace();
            }
            System.out.println("child run");
            return 123;
        }, executorService);
        System.out.println("main end");
        Integer integer = future.get();
        System.out.println(integer);
        executorService.shutdown();
    }
}

2、异步计算结果触发回调

当异步任务结束或者抛出异常时,还要根据结果来完成特定的操作,对于这种需求CompletableFuture也提供了方法进行实现。

	public CompletableFuture<T> whenComplete(
        BiConsumer<? super T, ? super Throwable> action) {
   
        return uniWhenCompleteStage(null, action);
    }

    public CompletableFuture<T> whenCompleteAsync(
        BiConsumer<? super T, ? super Throwable> action) {
   
        return uniWhenCompleteStage(asyncPool, action);
    }

    public CompletableFuture<T> whenCompleteAsync(
        BiConsumer<? super T, ? super Throwable> action, Executor executor) {
   
        return uniWhenCompleteStage(screenExecutor(executor), action);
    }
    public CompletableFuture<T> exceptionally(
        Function<Throwable, ? extends T> fn) {
   
        return uniExceptionallyStage(fn);
    }
2.1 whenComplete()与whenCompleteAsync()使用与源码解析

根据源码可知,上述三个方法都会接收BiConsumer并调用uniWhenCompleteStage,BiConsumer用于定义后续处理业务,处理正常计算结果或异常情况。uniWhenCompleteStage主要用于判断任务执行状态以及构建任务。
值得注意的一点是,whenComplete是在当前任务线程中继续执行指定的特定处理,而whenCompleteAsync会将指定的任务交给线程池另开启一个线程来执行。

// 使用whenComplete
public class whenCompleteDemo {
   
    public static void main(String[] args) {
   
        ExecutorService executor = Executors.newFixedThreadPool(100);
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
   
            System.out.println("异步任务线程:" + Thread.currentThread().getName());
            try {
   
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
   
                e.printStackTrace();
            }
            System.out.println("child run");
            return 123;
        }, executor);

        future.whenComplete((integer, throwable) -> {
   
            System.out.println("结果触发任务线程:" +Thread.currentThread().getName());
            System.out.println("特定任务执行");
        });
        executor.shutdown();
        System.out.println("main end");
    }
}

执行结果:

main end
异步任务线程:pool-1-thread-1
child run
结果触发任务线程:pool-1-thread-1
特定任务执行

根据执行结果可知,异步任务结束后,当使用whenComplete()时,后续的特定处理任务使用的线程与异步任务线程相同。

// 使用whenCompleteAsync()
public class whenCompleteAsyncDemo {
   
    public static void main(String[] args) throws ExecutionException, InterruptedException {
   
        ExecutorService executor = Executors.newFixedThreadPool(100);
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
   
            System.out.println("异步任务线程:" + Thread.currentThread().getName());
            try {
   
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
   
                e.printStackTrace();
            }
            System.out.println("child run");
            return 123;
        }, executor);

        CompletableFuture<Integer> future1 = future.whenCompleteAsync((integer, throwable) -> {
   
            System.out.println("结果触发任务线程:" + Thread.currentThread().getName());
            System.out.println("特定任务执行"
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值