• Java多线程开发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 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 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 runAsync(Runnable runnable)。

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

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

     

    2:有返回值的方法

    ​public static  CompletableFuture supplyAsync(Supplier supplier)

     public static  CompletableFuture supplyAsync(Supplier 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 futureA = CompletableFuture.supplyAsync(() ->
            {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("执行任务A");
                return "任务A";
            }, executor);
            CompletableFuture futureB = CompletableFuture.supplyAsync(() -> {
                System.out.println("执行任务B");
                return "任务B";
            }, executor);
            CompletableFuture 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 futureA = CompletableFuture.supplyAsync(() -> 10, executor);
            CompletableFuture 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 future1 = CompletableFuture.supplyAsync(() -> {
                System.out.println("查询商品信息1");
                return "future1";
            }, executor);
    ​
            CompletableFuture future2 = CompletableFuture.supplyAsync(() -> {
                System.out.println("查询商品信息2");
                return "future2";
            }, executor);
    ​
            CompletableFuture future3 = CompletableFuture.supplyAsync(() -> {
                System.out.println("查询商品信息3");
                return "future3";
            }, executor);
    ​
            final CompletableFuture voidCompletableFuture = CompletableFuture.allOf(future1, future2, future3);
            voidCompletableFuture.get();
            System.out.println("end...future1的结果:" + future1.get() + ",future2的结果:" + future2.get() + ",future3的结果:" + future3.get());
    复制代码

    ​输出结果

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

    聊了这么多你应该对我刚开始写的那段代码了如指掌。这么好用的类,欢迎你分享给其他的人,让更多人知晓一下。它运用到开发中,应该能为你的开发提供很多的便利。一束光,二束光,三束光。分享的多了文章慢慢就回也得更好看,更精彩了。

     

  • 相关阅读:
    Prefix-Tuning源码解析
    (Java版)转反串符字累很天聊他和长学海云 ,话说着倒欢喜三张身彼施还道之彼以算打长学海云是于
    【JavaScript复习六】内置对象string定位类获取方法
    测试工程师提升方向,提升产品思维提高测试效率......
    jmeter 简单数据写入器 创建文件失败
    [附源码]java毕业设计房屋租赁系统
    开源图编辑库 NebulaGraph VEditor 的设计思路分享
    04、JavaWeb启程——数据库
    Java多线程学习入门(五):ThreadLocal以及对象内存布局
    Nginx 学习(八)Nginx实现用IP测试灰度发布
  • 原文地址:https://www.cnblogs.com/scott1102/p/17233824.html