Java多线程开发工具之CompletableFuture的应用详解

 更新时间:2023年03月20日 11:30:31   作者:程序员xiaozhang  
做Java编程,难免会遇到多线程的开发,但是JDK8这个CompletableFuture类很多开发者目前还没听说过,但是这个类实在是太好用了,本文就来聊聊它的应用吧

做Java编程,难免会遇到多线程的开发,但是JDK8这个CompletableFuture类很多开发者目前还没听说过,但是这个类实在是太好用了,了解它的一些用法后相信你会对它爱不释手(呸渣男,咋对谁都爱不释手呢),好了我先简单举个列子,告诉你用它有多好。Single Dog拿一个Appointment来举个列子,如下:

/**
     * 女神化完妆之后,还需要一小会选衣服,不过分吧。
     * 也就是说我们现在有2个异步任务,第一个是化妆,第二个是选衣服。
     * 选衣服要在化妆完成之后进行,这两个任务是串行
     */
    public static void main(String[] args) {
        // 线程池我前面的文章聊过,怎么配置可以去了解一下
       ThreadPoolExecutor threadPool= new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
        //任务1
        CompletableFuture<String> makeUpFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + "-女神,开始化妆了");
            try {
                // 化妆的时间
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "化妆完毕了。";
        }, threadPool);
       //任务2,makeUp是调用方,意思是makeUpFuture执行完后再执行
        CompletableFuture<String> dressFuture = makeUpFuture.thenApply((result) -> {
            System.out.println(Thread.currentThread().getName() + "-女神" + result + "我开始选衣服啦,好了叫你!");
            try {
                // 换衣服的时间
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return result + "衣服也选好了,走出去玩吧!";
        });
        dressFuture.thenAccept((result) -> {
            System.out.println(Thread.currentThread().getName() + "-" + result);
        });
    }

上面的2个任务也可以理解为我们开发中要实现的不同功能,看明白前面的列子了吧?用它来写多线程运用的多丝滑。那我们就先讲一下它的核心的静态的方法,推荐用它的静态方法不要直接new对象。

1:无返回值的静态方法:

​public static CompletableFuture<Void> runAsync(Runnable runnable)。

public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor) 。

上面一个2个方法,如果没有指定Executor就使用默认的ForkJoinPool.commonPool()线程池,如果指定线程池就使用指定的。

2:有返回值的方法

​public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)

 public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)

如果开始的代码你还看不懂那介绍了上面的几个方法就先小试牛刀一下:

ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
​
        CompletableFuture.runAsync(() -> {
            System.out.println(Thread.currentThread().getName());
            int i = 10 / 2;
            System.out.println("运行的结果是:" + i);
        }, threadPool);
​
        CompletableFuture future = CompletableFuture.supplyAsync(() -> {
                    try {
                        Thread.sleep(2);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return "Hello World";
                }, threadPool);
        System.out.println(future.get());

好了讲过它的使用方法了那我们就聊一下它的几个使用的场景,开发中这写场景应该会使用到。

​1:执行任务 A,执行任务B,待任务B执行完成后,用B的返回值区执行任务C。

ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
        CompletableFuture<String> futureA = CompletableFuture.supplyAsync(() ->
        {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("执行任务A");
            return "任务A";
        }, executor);
        CompletableFuture<String> futureB = CompletableFuture.supplyAsync(() -> {
            System.out.println("执行任务B");
            return "任务B";
        }, executor);
        CompletableFuture<String> futurec = futureB.thenApply((b) -> {
            System.out.println("执行任务C");
            System.out.println("参数:" + b);
            return "a";
        });
        System.out.println(futurec.get());

​运行结果,注意我上面没说B一定要在A执行以后执行。

场景2:多个任务串联执行,下一个任务的执行依赖上一个任务的结果,每个任务都有输入和输出。

ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
        CompletableFuture futureA = CompletableFuture.supplyAsync(() -> "Hello", executor);
        CompletableFuture futureB = futureA.thenApply((a) -> a + " World");
        CompletableFuture futureC = futureB.thenApply((b) -> b);
        System.out.println(futureC.join());

​输出结果,开发中的经典场景输出:

​场景3:thenCombineAsync 联合 futureA和futureB的返回结果,然后在返回相关的数据

ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
        CompletableFuture<Integer> futureA = CompletableFuture.supplyAsync(() -> 10, executor);
        CompletableFuture<Integer> futureB = CompletableFuture.supplyAsync(() -> 20, executor);
        CompletableFuture futureC = futureA.thenCombineAsync(futureB, (r1, r2) -> {
            System.out.println("r1的值为:" + r1 + ":r2的值为:" + r2);
            return r1 + r2;
        });
        System.out.println(futureC.get());

​结果输出:

 好了聊完几个场景那就写一个在开发中的经典运用。

ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 10, 10, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(10), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
        System.out.println("start...");
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品信息1");
            return "future1";
        }, executor);
​
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品信息2");
            return "future2";
        }, executor);
​
        CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品信息3");
            return "future3";
        }, executor);
​
        final CompletableFuture<Void> voidCompletableFuture = CompletableFuture.allOf(future1, future2, future3);
        voidCompletableFuture.get();
        System.out.println("end...future1的结果:" + future1.get() + ",future2的结果:" + future2.get() + ",future3的结果:" + future3.get());

​输出结果

​这个经典的应用相信你可以在你的开发中进行套用,然后灵活的运用。当然这个类还有很多的方法,我这里只写了部分介绍了部分场景作为一个引子,如果想了解它的更多的应用可以看它的API的文档。

到此这篇关于Java多线程开发工具之CompletableFuture的应用详解的文章就介绍到这了,更多相关Java CompletableFuture内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • spring boot项目没有mainClass如何实现打包运行

    spring boot项目没有mainClass如何实现打包运行

    这篇文章主要介绍了spring boot项目没有mainClass如何实现打包运行,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • 利用JWT如何实现对API的授权访问详解

    利用JWT如何实现对API的授权访问详解

    这篇文章主要给大家介绍了关于利用JWT如何实现对API的授权访问的相关资料,需要的朋友可以参考下
    2018-09-09
  • 详解spring cloud中使用Ribbon实现客户端的软负载均衡

    详解spring cloud中使用Ribbon实现客户端的软负载均衡

    这篇文章主要介绍了详解spring cloud中使用Ribbon实现客户端的软负载均衡,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-01-01
  • 基于Lucene的Java搜索服务器Elasticsearch安装使用教程

    基于Lucene的Java搜索服务器Elasticsearch安装使用教程

    Elasticsearch也是用Java开发的,并作为Apache许可条款下的开放源码发布,能够做到实时搜索,且稳定、可靠、快速,安装使用方便,这里我们就来看一下基于Lucene的Java搜索服务器Elasticsearch安装使用教程:
    2016-06-06
  • 解析JavaSe的抽象类和接口

    解析JavaSe的抽象类和接口

    这篇文章主要为大家详细介绍了JavaSe的抽象类和接口,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • 在Spring-Boot中如何使用@Value注解注入集合类

    在Spring-Boot中如何使用@Value注解注入集合类

    这篇文章主要介绍了在Spring-Boot中如何使用@Value注解注入集合类的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • Java多线程之Semaphore实现信号灯

    Java多线程之Semaphore实现信号灯

    这篇文章主要给大家分享的是Java多线程之Semaphore实现信号灯的练习,emaphore是计数信号量。Semaphore管理一系列许可证。每个acquire方法阻塞,直到有一个许可证可以获得然后拿走一个许可证;下面一起进入文章学习Semaphore的具体内容
    2021-10-10
  • Spring MVC获取查询参数及路径参数代码实例

    Spring MVC获取查询参数及路径参数代码实例

    这篇文章主要介绍了Spring MVC获取查询参数及路径参数代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • java线程池使用后到底要关闭吗

    java线程池使用后到底要关闭吗

    这篇文章主要给大家介绍了关于java线程池使用后到底要不要关闭的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-01-01
  • SpringMVC获取请求参数的方法

    SpringMVC获取请求参数的方法

    这篇文章主要介绍了SpringMVC获取请求参数的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2025-04-04

最新评论