CompletableFuture学习

CompletableFuture详解

JDK1.8引入的新的Future,常用于异步编程之中,所谓异步编程,简单来说就是:“程序运算与应用程序主线程在不同的线程上完成,并且程序运算的线程能够向主线程通知其进度,以及成功与失败与否的非阻塞式编码方式”,

CompletableFuture的基本用法

CompletableFuture首先是一个Future。

  public static void main(String[] args) {
        //double 类型的 CompletableFuture
        final CompletableFuture<Double> completableFuture = new CompletableFuture();
        //提交异步任务
        Executors.newCachedThreadPool().submit(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
                System.out.println("finished");
                //执行结束
                completableFuture.complete(1234.5D);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        //非阻塞获取异步任务的计算结果,和宁县,此刻异步任务未执行结束,那么可以采用默认值的方式
        //(该方法也可以被认为是放弃异步任务的执行结果,但不会取消异步任务的执行 )
        try {
            assert completableFuture.get() == 1234.5D;
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

任务的异步运行

CompletableFuture除了具备Future的基本特性之外,还可以直接使用它执行异步任务。通常情况下,任务的类型为Suppiler和Runnable,前者非常类似于Callable接口,可返回指定类型的运算结果,后者仍然只是关注异步任务运行本身。

异步执行Supplier

可以直接调用CompletableFuture的静态方法supplyAsync异步执行Supplier类型的任务。


CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 354);

// 另一个重载 方法,运行传入 ExecutorService
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 354, Executors.newCachedThreadPool());

异步执行Runnable类型的任务

也可以直接调用CompletableFuture的静态方法runAsync 异步执行Runnable类型的任务。

CompletableFuture.runAsync(() -> {
    System.out.println("async task .");
});

异步任务链

CompletableFuture还允许将执行的异步任务结果继续交由下一级任务来执行,下一任务还可以有下一次,以此类推,这样就可以形成一个异步任务链或者任务pipeline。

thenApply :以同步的方式继续处理上一个异步任务的结果

    /**
     * 以同步的方式继续执行上一个异步任务的结果
     * supplyAsync 的 计算结果为 Java
     * thenApply 继续处理 “Java” ,返回字符串的长度
     * supplyAsync和thenApply 的任务执行是同一个线程
     */
    static void thenApply() throws ExecutionException, InterruptedException {
        final ExecutorService executor = Executors.newFixedThreadPool(3);
        final CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " supplyAsync");
            return "Java";
        }, executor).thenApply(e -> {
            System.out.println(Thread.currentThread().getName() + " thenApply");
            System.out.println(Thread.currentThread().getName() + " " + e);
            return e.length();
        });
        System.out.println(future.get());
    }

thenApplyAsync: 以异步的方式继续处理上一个异步任务的结果

 /**
     * thenApplyAsync 的计算结果为“Java”
     * thenApplyAsync 继续处理“Java”,返回字符串的长度
     */
    static void thenApplyAsync() throws ExecutionException, InterruptedException {
        final ExecutorService executor = Executors.newFixedThreadPool(3);
        final CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " supplyAsync");
            return "Java";
        }, executor).thenApplyAsync(e -> {
            System.out.println(Thread.currentThread().getName() + " thenApplyAsync");
            System.out.println(Thread.currentThread().getName() + " " + e);
            return e.length();
        });
        System.out.println(future.get());
    }

thenAccept : 以同步的方式消费上一个异步任务的结果

    /**
     * thenAccept : 以同步的方式消费上一个异步任务的结果
     */
    static void thenAccept() throws ExecutionException, InterruptedException {
        final ExecutorService executor = Executors.newFixedThreadPool(3);
        CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " supplyAsync");
            return "Java";
        }, executor).thenAccept(e -> {
            System.out.println(Thread.currentThread().getName() + " thenAccept");
            System.out.println(Thread.currentThread().getName() + " " + e);
        });
        executor.shutdown();
    }

thenAcceptAsync 以异步的方式消费上一个异步任务的结果

 /**
     * thenAcceptAsync 以异步的方式消费上一个异步任务的结果
     */
    static void thenAcceptAsync() throws ExecutionException, InterruptedException {
        final ExecutorService executor = Executors.newFixedThreadPool(3);
        CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " supplyAsync");
            return "Java";
        }, executor).thenAcceptAsync(e -> {
            System.out.println(Thread.currentThread().getName() + " thenAcceptAsync");
            System.out.println(Thread.currentThread().getName() + " " + e);
        });
        executor.shutdown();
    }

在任务链的末端,如果执行的任务既不想对上一个任务的输出做进一步处理,又不想消费上一个任务的输出结果。那么可以使用thenRun或者thenRunSync方法来执行Runnable任务。

thenRun 以异步的而方式执行Runable任务

static void thenRun() throws ExecutionException, InterruptedException {
    final ExecutorService executor = Executors.newFixedThreadPool(3);
    CompletableFuture.supplyAsync(() -> {
        System.out.println(Thread.currentThread().getName() + " supplyAsync");
        return "Java";
    }, executor).thenAcceptAsync(e -> {
        System.out.println(Thread.currentThread().getName() + " thenAcceptAsync");
        System.out.println(Thread.currentThread().getName() + " " + e);
    }).thenRunAsync(() -> {
        System.out.println("all of task completed." + Thread.currentThread().getName());
    });
}

合并多个Future

CompletableFuture还允许将若干个Future合并成一个Future的使用方式,可以通过thenCompose方法或者thenCombine方法来实现多个Future的合并

thenCompose 方法示例

void thenCompose() {
    //通过thenCompose将两个Future合并成一个Future
    final CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Java")
            //s 为上一个Future的计算结果
            .thenCompose(s -> CompletableFuture.supplyAsync(() -> s + " scala"));
    //合并后的Future通过thenApply方法组成任务链
    completableFuture.thenApply(String::toUpperCase)
            .thenAccept(System.out::println);
}

thenCombine 方法示例

void thenCombine() {
    final CompletableFuture<String> thenCombine = CompletableFuture.supplyAsync(() -> "Java")
            .thenCombine(CompletableFuture.supplyAsync(() -> " scala"),
                    //s1为第一个Future计算的结果,s2为第二个Future计算的结果 
                    (s1, s2) -> s1 + s2);
    thenCombine.thenApply(String::toUpperCase)
            .thenAccept(System.out::println);
}

多Future的并行计算

如果想多个独立CompletableFuture同时并行计算,可以借助allOf来完成,其类似于ExecutorService的invokeAll批量提交异步任务。

/**
 * 多Future的并行计算
 */
void allOf() throws ExecutionException, InterruptedException {
    //定义三个CompletableFuture
    final CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> "Java");
    final CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> "Parallel");
    final CompletableFuture<String> f3 = CompletableFuture.supplyAsync(() -> "Future");
    //批量执行 ,返回值是一个 void 类型的CompletableFuture
    final CompletableFuture<Void> future = CompletableFuture.allOf(f1, f2, f3).thenRun(() -> {
        try {
            System.out.println(f1.isDone() + " and result " + f1.get());
            System.out.println(f2.isDone() + " and result " + f2.get());
            System.out.println(f3.isDone() + " and result " + f3.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    });
    //阻塞等待运行结束
    future.get();
}

CompletableFuture总结

自JDK1.8以来,CompletableFuture的引入不仅很好地填充了Future的不足之处,还提供了非常遍历的异步编程方式,借助于CompletableFuture,我们可以很轻易地开发出异步运行的代码,甚至不用关心地城线程的维护和管理,只需要关注代码函数本身即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值