[多线程] 二:CompletableFuture

背景:

      CompletableFuture提供了一种观察者模式类似的机制,可以让任务执行完成后通知监听的一方。

     使用场景:多个任务异步执行,互不影响,提高应用的响应速度和吞吐量。

     提供了不用回调的API、以及可以回调的API。


 

常见API:

      runAsync:

        执行异步任务,该API没有回调。

//默认使用ForkJoinPool线程池
public static CompletableFuture<Void> runAsync(Runnable runnable)

//指定线程池
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)

       supplyAsync:

          执行异步任务,该API有返回值


// 使用默认的ForkJoinPool线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
// 有返回值 可以自定义线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)

        allOf、anyof:

           等待所有任务完成。


// 等待所有任务完成
CompletableFuture.allOf(future1, future2, future3).get();
CompletableFuture.allOf(future1, future2, future3).join();
 
// 只要任意一个任务完成即可  
CompletableFuture.anyOf(future1, future2, future3).get();
CompletableFuture.anyOf(future1, future2, future3).join();

        

获取返回值:

有三个API。

join:返回结果或者抛出一个unchecked异常(CompletionException),不需要显示捕获异常。
get:返回结果或者一个具体的异常(ExecutionException, InterruptedException),此方法继承至Future是堵塞的。
getNow:如果当前任务执行完成,返回执行结果,否则返回valueIfAbsent(默认值)。

 
    /**
     * 通过get获取方法
     */
    public void test1() {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "get方法需要显示捕获异常");
        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }
 
    /**
     * join 不需要显示捕获异常
     */
    public void test2() {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "join方法不需要显示捕获异常");
        System.out.println(future.join());
    }
 
    /**
     * getNow方法可以设置默认值
     * 在有效的时间内,未返回结果,则直接返回默认值
     */
    public void test3() {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "getNow获取返回值");
        System.out.println(future.getNow("默认值"));
    }

并行实践:

     

        long startMills = System.currentTimeMillis();
        System.out.println(startMills);
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {

                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return "1";
                }
        );
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {

                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return "2";
                }
        );

        CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(future1, future2);
        allOfFuture.thenRun(() -> System.out.println("All futures completed"));
        allOfFuture.join();
    



        long endMills = System.currentTimeMillis();
        System.out.println(endMills);

注意,这里join方法才能堵塞,allOf方法只是一个占位符。如果不调用join方法,这段代码不会有3秒的时间差。只有调用join、get等方法,才能达到future1、future2一起执行完,才接着下一步打印的操作。

 踩坑点:

        不设置线程池,其默认是利用共有的ForkJoinPool实现的异步。          

        随便拿个API看源码。

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
        return asyncSupplyStage(asyncPool, supplier);
}
private static final Executor asyncPool = useCommonPool ?
        ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
private static final boolean useCommonPool =
        (ForkJoinPool.getCommonPoolParallelism() > 1);

     可以看出来,并行程度高的话,会使用ForkJoinPool线程池的池子(commonPool)。

  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值