CompletableFuture原理解析和使用

一:原理说明

原理说了没啥用,先了解一下怎么用,先体会使用的过程,再去了解原理

CompletableFuture原理解析和使用_第1张图片

 

当前假若有一个任务正在执行,需要创建异步执行任务: 这个事交给异步线程去完成,主线程可以去做其他任务,这个异步线程任务可以将结果返回,主线程不需要阻塞等待获取结果

Callable,有结果的同步行为,
Runnable,无结果的同步行为,
Future,异步封装Callable/Runnable,
CompletableFuture,封装Future,

 

二:使用

使用一:当前假若有一个任务正在执行,需要创建异步执行任务: 这个事交给异步线程去完成,主线程可以去做其他任务,这个异步线程任务可以将结果返回,主线程不需要阻塞等待获取结果

  @Test
    public  void test() throws InterruptedException {
        MyTask task1 = new MyTask("task1",3L,1.1);

        /**
         * 一:创建异步线程任务
         */
        //1:
        // 创建异步执行任务: 这个地方表示的是目前需要做的事情,
        // 但是这个事交给异步线程去完成,主线程可以去做其他任务,
        // 这个异步线程任务可以将结果返回,主线程不需要阻塞等待获取结果
        //2:Callable,有结果的同步行为,
        //Runnable,无结果的同步行为
        //Future,异步封装Callable/Runnable,
        //CompletableFuture,封装Future,
        CompletableFuture cf = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println("开始执行异步任务");
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return task1.call();
        });

        /**
         * 二:执行成功
         */
        // 如果执行成功:
        cf.thenAccept((result) -> {
            try {
                System.out.println("异步任务执行完成结果通知-------");
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("异步执行结果是:price: " + result);
        });

        /**
         * 三:执行失败
         */
        cf.exceptionally((e) -> {
            System.out.println("执行失败----------");
            return null;
        });


        System.out.println("主线程继续执行------");
        // 主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:
        Thread.currentThread().join();

    }

 

 

 

使用二:

如果只是实现了异步回调机制, * 我们还看不出CompletableFuture相比Future的优势。 * CompletableFuture更强大的功能是,多个CompletableFuture可以串行执行, * 例如,定义两个CompletableFuture,第一个CompletableFuture根据证券名称查询证券代码, * 第二个CompletableFuture根据证券代码查询证券价格,这两个CompletableFuture实现串行操作如下:

 @Test
    public void test02() throws ExecutionException, InterruptedException {
        // 第一个任务:
        CompletableFuture task1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务一。。。。。");
            return "1";
        });
        // task1任务执行成功后,将任务1的结果作为入参执行任务2:
        //
        CompletableFuture task2 = task1.thenApplyAsync((code) -> {
            System.out.println("任务二。。。。。"+code);
            return fetchPrice(code);
        });
        // task2成功后打印结果:
        task2.thenAccept((result) -> {
            System.out.println("price: " + result);
        });
        // 主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:
        Thread.sleep(2000);

    }

 

使用三:

除了串行执行外,多个CompletableFuture还可以并行执行。例如,我们考虑这样的场景:
*
* 同时从新浪和网易查询证券代码,只要任意一个返回结果,
* 就进行下一步查询价格,查询价格也同时从新浪和网易查询,只要任意一个返回结果,就完成操作:

 

@Test
    public void test03() throws ExecutionException, InterruptedException {
        // 两个CompletableFuture执行异步查询:
        CompletableFuture task1 = CompletableFuture.supplyAsync(() -> {
            return queryCode("任务1", "https://finance.sina.com.cn/code/");
        });
        CompletableFuture task2 = CompletableFuture.supplyAsync(() -> {
            return queryCode("任务2", "https://money.163.com/code/");
        });

        // 用anyOf合并为一个新的CompletableFuture:
        CompletableFuture cfQuery = CompletableFuture.anyOf(task1, task2);

        // 两个CompletableFuture执行异步查询:
        CompletableFuture task1Result = cfQuery.thenApplyAsync((code) -> {
            return fetchPrice((String) code);
        });
        CompletableFuture task2Result = cfQuery.thenApplyAsync((code) -> {
            return fetchPrice((String) code);
        });

        // 用anyOf合并为一个新的CompletableFuture:
        CompletableFuture cfFetch = CompletableFuture.anyOf(task1Result, task2Result);

        // 最终结果:
        cfFetch.thenAccept((result) -> {
            System.out.println("price: " + result);
        });
        // 主线程不要立刻结束,否则CompletableFuture默认使用的线程池会立刻关闭:
        Thread.sleep(200);
        /**
         * 除了anyOf()可以实现“任意个CompletableFuture只要一个成功”,
         * allOf()可以实现“所有CompletableFuture都必须成功(allAll)”,这些组合操作可以实现非常复杂的异步流程控制。
         *
         * 最后我们注意CompletableFuture的命名规则:
         *
         * xxx():表示该方法将继续在已有的线程中执行;
         * xxxAsync():表示将异步在线程池中执行。
         */

    }











    static Double fetchPrice(String code) {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
        }
        if (Math.random() < 0.3) {
            throw new RuntimeException("fetch price failed!");
        }
        return 5 + Math.random() * 20;
    } 
  

 

// 直接创建
CompletableFuture c0 = new CompletableFuture();
// 直接创建一个已经做完的蛋糕
val c1 = CompletableFuture.completedFuture("cake");
// 无返回值异步任务,会采用内部forkjoin线程池
val c2 = CompletableFuture.runAsync(()->{});
// 无返回值异步任务,采用定制的线程池
val c3 = CompletableFuture.runAsync(()->{}, newSingleThreadExecutor());
// 返回值异步任务,采用定制的线程池
val c4 = CompletableFuture.supplyAsync(()-> "cake", newSingleThreadExecutor());
// 返回值异步任务,采用内部forkjoin线程池
val c5 = CompletableFuture.supplyAsync(()-> "cake");
// 只要有一个完成,则完成,有一个抛异常,则携带异常
CompletableFuture.anyOf(c1, c2, c3, c4, c5);
// 当所有的 future 完成时,新的 future 同时完成
// 当某个方法出现了异常时,新 future 会在所有 future 完成的时候完成,并且包含一个异常.
CompletableFuture.allOf(c1, c2, c3, c4, c5);


//不抛出中断异常,看着你做蛋糕
//阻塞
cf.join();
//有异常,看着你做蛋糕
//阻塞
cf.get();
//有异常,看着你做蛋糕一小时
//阻塞
cf.get(1, TimeUnit.HOURS);
//蛋糕做好了吗?做好了我直接吃你做的,做不好我吃我的
//非阻塞
cf.getNow("my cake");
// 我问糕点师:蛋糕是否不做了?
//非阻塞
cf.isCancelled();
//我问糕点师:蛋糕是否做糊了?
//非阻塞
cf.isCompletedExceptionally();
// 我问糕点师:蛋糕做完了吗?
//非阻塞
cf.isDone();

 

 

 

三:原理

CompletableFuture原理解析和使用_第2张图片

CompletableFuture同时实现了两个接口,分别为Future和CompletionStage,CompletionStage是CompletableFuture提供的一些非常丰富的接口,可以借助这些接口来实现非常复杂的异步计算工作.



 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(Java基础)