CompletableFuture3-简介及使用(创建对象、有无返回值异步任务、回调函数、需要注意的坑)

一.CompletableFuture简介

   为了满足Java在处理异步任务的一些不足,比如说对返回值获取不友好等,在1.8版本推出了CompletableFuture,它实现了Future和CompletionStage接口,拥有Futrue的全部功能,并拥有更加强大的异步回调,执行级联任务等等优点.

在这里插入图片描述

二.CompletableFuture简单入门使用

1.创建对象

对于一般Java对象来说,最常见得就是直接new一个对象,但是CompletableFuture还是有点特别得,我们可以看到文档中已经说明,通过构造器会创建一个不完整得CompletableFuture对象.所以是不推荐使用空参构造方法来创建一个CompletableFuture对象得.
在这里插入图片描述

那要怎样获得这个对象呢?我们可以通过两组,四个方法进行获取.
在这里插入图片描述

这里需要注意Executor(线程池)得参数说明:
在这里插入图片描述
并且这里得ForkJoinPool.commonPool()创建得线程是守护线程(不理解守护线程的,可以看一下这个用户线程和守护线程的区别),这一点在第三节中会证明.

2.代码演示-无返回值类型

方法:CompletableFuture.runAsync()
使用自带得线程池(注意自带得是守护线程)

 //当我们传入任务返回对象得时候,线程任务已经开始执行了
        //使用自带得线程池(注意自带得是守护线程)
        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
            System.out.println(Thread.currentThread().getName());
        });
        //completableFuture 实现了Future<T>, CompletionStage<T> 接口,自然也会有Future得get()方法
        System.out.println(completableFuture.get());

输出值:
在这里插入图片描述
使用自定义得线程池(默认用户线程)

ExecutorService executorService = Executors.newFixedThreadPool(3);
        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
            System.out.println(Thread.currentThread().getName());
        },executorService);
        //completableFuture 实现了Future<T>, CompletionStage<T> 接口,自然也会有Future得get()方法
        System.out.println(completableFuture.get());
        //使用线程池,记得进行关闭
        executorService.shutdown();

输出值:
在这里插入图片描述

3.代码演示-有返回值类型

方法:CompletableFuture.supplyAsync
这里直接演示用自定义线程池得方法.

 ExecutorService executorService = Executors.newFixedThreadPool(3);
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName());
            return "hello supplyAsync";
        }, executorService);
        //completableFuture 实现了Future<T>, CompletionStage<T> 接口,自然也会有Future得get()方法
        System.out.println(completableFuture.get());
        //使用线程池,记得进行关闭
        executorService.shutdown();

输出结果:
在这里插入图片描述

三.通用演示,传入回调函数,减少阻塞

我们知道CompletableFuture拥有比Future更强大的功能,能够减少阻塞和轮询.
我们可以传入一个回调函数,当异步任务完成得时候,自动执行回调方法.
举例:使用自带线程池:

 CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("开始执行异步任务...这个任务预计耗时1s");
            System.out.println("执行异步任务线程为:"+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "hello supplyAsync";
        /**
         * 传入回调函数,当顺利执行完毕后,会自动调用该函数
         * 第一个参数result就是异步任务返回得结果
         * 第二个参数e,就是这个过程中出现得异常对象
         */
        }).whenComplete((result,e)->{
            System.out.println("异步任务已经执行完毕...获取结果:"+result);
        /**
         * 当任务出现异常会走到这个分支,进行异常得处理
         * 这里得参数还是异常
         */
        }).exceptionally((e) -> {
            e.printStackTrace();
            System.out.println("出现异常:"+e.getCause());
            //出现异常后返回得结果
            return null;
        });

        System.out.println("主线程开始忙其他得事情...");

输出结果:
在这里插入图片描述
   细心得同学可能已经发现有问题了,程序并没有输出返回结果,直接就结束了,这是为什么呢?

   因为我们使用的是自带得线程池,还记得前面说自带得线程池创建出来的线程都是守护线程吗,这里就体现出来得,因为main线程先于异步任务线程执行完毕,此时JVM中已没有用户线程了,所以守护线程自动被关闭.所以使用该类最好使用自定义线程池

所以我们需要改进一下,使用我们自定义得线程池,改进代码如下:

 ExecutorService executorService = Executors.newFixedThreadPool(3);
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("开始执行异步任务...这个任务预计耗时1s");
            System.out.println("执行异步任务线程为:"+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "hello supplyAsync";
        /**
         * 传入回调函数,当顺利执行完毕后,会自动调用该函数
         * 第一个参数result就是异步任务返回得结果
         * 第二个参数e,就是这个过程中出现得异常对象
         */
        },executorService).whenComplete((result,e)->{
            System.out.println("异步任务已经执行完毕...获取结果:"+result);
        /**
         * 当任务出现异常会走到这个分支,进行异常得处理
         * 这里得参数还是异常
         */
        }).exceptionally((e) -> {
            e.printStackTrace();
            System.out.println("出现异常:"+e.getCause());
            //出现异常后返回得结果
            return null;
        });

        System.out.println("主线程开始忙其他得事情...");

        executorService.shutdown();

输出结果:
在这里插入图片描述

四.总结.

通过以上小练习我们能够知道CompletableFuture是具有如下这些优点的.
在这里插入图片描述

在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员bling

义父,感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值