CompletableFuture使用

Java CompletableFuture使用

既然 CompletableFuture 类实现了 CompletionStage 接口,首先我们需要理解这个接口的契约。它代表了一个特定的计算的阶段,可以同步或者异步的被完成。你可以把它看成一个计算流水线上的一个单元,最终会产生一个最终结果,这意味着几个 CompletionStage 可以串联起来,一个完成的阶段可以触发下一阶段的执行,接着触发下一次,接着……

除了实现 CompletionStage 接口, CompletableFuture 也实现了 future 接口, 代表一个未完成的异步事件。CompletableFuture 提供了方法,能够显式地完成这个future,所以它叫 CompletableFuture 。

1、 创建一个完成的CompletableFuture

最简单的例子就是使用一个预定义的结果创建一个完成的CompletableFuture,通常我们会在计算的开始阶段使用它。

   @Test
    public void completedFutureExample() {
        CompletableFuture cf = CompletableFuture.completedFuture("message");
        assertTrue(cf.isDone());
        assertEquals("message", cf.getNow(null));
    }

getNow(null) 方法在future完成的情况下会返回结果,就比如上面这个例子,否则返回null (传入的参数)。

2、运行一个简单的异步阶段

    @Test
    public void runAsyncExample() {
        CompletableFuture cf = CompletableFuture.runAsync(() -> {
            System.out.println(Thread.currentThread().getName());
            System.out.println(Thread.currentThread().isDaemon());
        });
        System.out.println(cf.isDone());
    }

3、在前一个阶段上应用函数

下面这个例子使用前面 #1 的完成的CompletableFuture, #1返回结果为字符串 message ,然后应用一个函数把它变成大写字母。

then 意味着这个阶段的动作发生当在前一个阶段正常完成之后。本例中,当前节点完成,返回字符串 message 。

Apply 意味着返回的改阶段将会对前一阶段的结果应用一个函数。

函数的执行会被阻塞 ,这意味着 getNow() 只有打斜操作被完成后才返回。

@Test
public void thenApplyExample() {
    CompletableFuture cf = CompletableFuture.completedFuture("message").thenApply(s -> {
        return s.toUpperCase();
    });
    System.out.println(cf.join());
}

4、在前一个阶段上异步应用函数

通过调用异步方法(方法后边加Async后缀),串联起来的CompletableFuture可以异步地执行(使用ForkJoinPool.commonPool())。

 @Test
    public void thenApplyAsyncExample() {
        CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(s -> {
            assertTrue(Thread.currentThread().isDaemon());
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {

            }
            return s.toUpperCase();
        });
        System.out.println(cf.join());
    }

5、使用定制的Executor在前一个阶段上异步应用函数
异步方法一个非常有用的特性就是能够提供一个Executor来异步地执行CompletableFuture。这个例子演示了如何使用一个固定大小的线程池来应用大写函数。

   @Test
    public void thenApplyAsyncWithExecutorExample() {
        ExecutorService executor = Executors.newFixedThreadPool(3, new ThreadFactory() {
            int count = 1;
            @Override
            public Thread newThread(Runnable runnable) {
                return new Thread(runnable, "custom-executor-" + count++);
            }
        });

        CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(s -> {
            System.out.println((Thread.currentThread().getName()));
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {

            }
            return s.toUpperCase();
        }, executor);
        System.out.println(cf.join());
    }

6、消费前一阶段的结果

如果下一阶段接收了当前阶段的结果,但是在计算的时候不需要返回值(它的返回类型是void), 那么它可以不应用一个函数,而是一个消费者, 调用方法也变成了 thenAccept

    @Test
    public void thenAcceptExample() {
        StringBuilder result = new StringBuilder();
        CompletableFuture.completedFuture("thenAccept message")
                .thenAccept(s -> result.append(s));
        System.out.println(result);
        assertTrue("Result was empty", result.length() > 0);
    }

7、异步地消费前一阶段的结果

    @Test
    public void thenAcceptAsyncExample() {
        StringBuilder result = new StringBuilder();
        CompletableFuture cf = CompletableFuture.completedFuture("thenAcceptAsync message")
                .thenAcceptAsync(s -> result.append(s));
        cf.join();
        assertTrue("Result was empty", result.length() > 0);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值