Java异步编程CompletableFuture使用方法

使用之前先要定义一个线程池,也可不定义使用默认的线程池,这里先简单定义一个线程池。

ExecutorService executor = Executors.newFixedThreadPool(10);

异步调用方式

1.supplyAsync()有返回值

 /**
     * supplyAsync:有返回值
     */
    @Test
    public void test5() throws Exception {
        System.out.println("主线程开始:" + Thread.currentThread().getName());
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() ->
        {
            //执行任务
            System.out.println("子线程:" + Thread.currentThread().getName() + "正在执行任务...");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "子线程执行完成...";
        }, executor);
        System.out.println("获取返回值:" + future.get());
        System.out.println("主线程结束:" + Thread.currentThread().getName());
    }

在这里插入图片描述

2.runAsync()无返回值

    /**
     * runAsync:无返回值
     */
    @Test
    public void test4() throws ExecutionException, InterruptedException {
        System.out.println("主线程开始:" + Thread.currentThread().getName());
        CompletableFuture<Void> future = CompletableFuture.runAsync(() ->
        {
            //执行任务
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子线程:" + Thread.currentThread().getName() + ":正在执行任务...");
        }, executor);
        System.out.println("获取返回值:" + future.get());
        System.out.println("主线程结束:" + Thread.currentThread().getName());
    }

在这里插入图片描述

future.get()方法是获取异步线程的返回值,会使主线程阻塞直到获取结果。

多任务结果处理

1.allOf()方法

CompletableFuture.allOf()方法会收集所有异步处理结果,join()方法会阻塞等待所有线程执行完毕。

    @Test
    public void test5() throws InterruptedException {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() ->
        {
            System.out.println("商品名称");
            return "华为手机";
        }, TestAsync.executor);

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() ->
        {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("商品属性");
            return "8G+256G";
        }, TestAsync.executor);

        CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() ->
        {
            System.out.println("商品价格");
            return "4999元";
        }, TestAsync.executor);

        //收集所有异步处理结果
        CompletableFuture<Void> futures = CompletableFuture.allOf(future1, future2, future3);
        //阻塞等待所有任务执行结束,返回结果为null
        System.out.println(futures.join());

        System.out.println("=====主线程=====");
        Thread.sleep(500);

        //join()获取结果不再阻塞
        System.out.println(future1.join() + ":" + future2.join() + ":" + future3.join());
    }

在这里插入图片描述

2.anyOf()方法

CompletableFuture.anyOf()的含义是只要有任意一个CompletableFuture结束,就可以获取结果做接下来的事情,而无须像AllOf()那样,等待所有的任务结束。

    @Test
    public void test6() {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() ->
        {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("商品名称");
            return "华为手机";
        }, TestAsync.executor);

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() ->
        {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("商品属性");
            return "8G+256G";
        }, TestAsync.executor);

        CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() ->
        {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("商品价格");
            return "4999元";
        }, TestAsync.executor);

        CompletableFuture<Object> futures = CompletableFuture.anyOf(future1, future2, future3);
        //阻塞等待最先的任务执行完成,返回最先完成的任务返回结果,无需等待所有任务执行完成
        System.out.println("执行结果: " + futures.join());

        System.out.println("=====主线程=====");
    }

在这里插入图片描述

异步结果回调处理

1.thenApply()和thenApplyAsync()

此方法表示某个任务执行完成后执行的动作,即回调方法,会将该任务的执行结果即方法返回值作为入参传递到回调方法中,回调方法有返回值。

(1).thenApplyAsync()测试代码:

    @Test
    public void test4() throws ExecutionException, InterruptedException {
        System.out.println("主线程名: " + Thread.currentThread().getName());

        //父任务
        CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("父线程名: " + Thread.currentThread().getName());
            return 1;
        });
        //子任务
        CompletableFuture<Integer> cf2 = cf1.thenApplyAsync((result) -> {
            System.out.println("子线程名: " + Thread.currentThread().getName());
            result += 2;
            return result;
        });

        //等待父任务执行完成
        System.out.println("父任务结果-> " + cf1.get());
        //等待子任务执行完成
        System.out.println("子任务结果-> " + cf2.get());
    }

在这里插入图片描述
测试结果分析:使用thenApplyAsync()回调方法,父任务线程和子任务线程用的是默认线程池中的同一个线程。

(2).thenApply()测试代码:

	@Test
    public void test5() throws ExecutionException, InterruptedException {
        System.out.println("主线程名: " + Thread.currentThread().getName());

        //父任务
        CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("父线程名: " + Thread.currentThread().getName());
            return 1;
        });
        //子任务
        CompletableFuture<Integer> cf2 = cf1.thenApply((result) -> {
            System.out.println("子线程名: " + Thread.currentThread().getName());
            result += 2;
            return result;
        });

        //等待父任务执行完成
        System.out.println("父任务结果-> " + cf1.get());
        //等待子任务执行完成
        System.out.println("子任务结果-> " + cf2.get());
    }

在这里插入图片描述
测试结果分析:使用thenApply()回调方法,父任务线程用的是默认线程池中的线程,子任务用的是主线程。

2.thenAccept()和thenAcceptAsync()

此方法与上面的两个方法区别是回调方法没有返回值。

(1).thenAccept()测试代码:

    @Test
    public void test6() throws ExecutionException, InterruptedException {
        System.out.println("主线程名: " + Thread.currentThread().getName());

        //父任务
        CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("父线程名: " + Thread.currentThread().getName());
            return 1;
        });
        //子任务
        CompletableFuture<Void> cf2 = cf1.thenAccept((result) -> {
            System.out.println("子线程名: " + Thread.currentThread().getName());
        });

        //等待父任务执行完成
        System.out.println("父任务结果->" + cf1.get());
        //等待子任务执行完成
        System.out.println("子任务结果->" + cf2.get());
    }

在这里插入图片描述
测试结果分析:使用thenAccept()回调方法,父任务线程用的是默认线程池中的线程,子任务用的是主线程。

(2).thenAcceptAsync()测试代码:

	@Test
    public void test7() throws ExecutionException, InterruptedException {
        System.out.println("主线程名: " + Thread.currentThread().getName());

        //父任务
        CompletableFuture<Integer> cf1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("父线程名: " + Thread.currentThread().getName());
            return 1;
        });
        //子任务
        CompletableFuture<Void> cf2 = cf1.thenAcceptAsync((result) -> {
            System.out.println("子线程名: " + Thread.currentThread().getName());
        });

        //等待父任务执行完成
        System.out.println("父任务结果->" + cf1.get());
        //等待子任务执行完成
        System.out.println("子任务结果->" + cf2.get());
    }

在这里插入图片描述
测试结果分析:使用thenAcceptAsync()回调方法,父任务线程和子任务线程用的是默认线程池中的同一个线程。

3.exceptionally()

exceptionally()方法表示任务执行异常时执行的回调方法,并且有抛出异常作为参数,传递到回调方法,测试代码:

 	@Test
    public void test6() throws ExecutionException, InterruptedException {
        CompletableFuture<Double> future = CompletableFuture.supplyAsync(() -> {
            double random = Math.random();
            if (random < 0.5) {
                int i = 5 / 0;
            }
            System.out.println("正常结束");
            return random;
        }).exceptionally(e -> {
            //发生异常后才会执行
            System.out.println("异常信息: " + e.getMessage());
            return Math.random();
        });
        System.out.println(future.get());
    }

测试结果:
(1).正常情况:
在这里插入图片描述
(2).异常情况:
在这里插入图片描述
以上可看出,supplyAsync()方法发生异常才会执行exceptionally()方法。

实例应用

    private List<MediaFileDTO> ossSupplyAsync(List<MediaFileDTO> records) {
        List<CompletableFuture<MediaFileDTO>> futureList = new ArrayList<>();
        List<MediaFileDTO> listData = new ArrayList<>();
        records.forEach(record -> {
            CompletableFuture<MediaFileDTO> future = CompletableFuture.supplyAsync(() -> {
                if (record.getFileName().endsWith(".jpeg") || record.getFileName().endsWith(".jpg")) {
                    String objectKey = record.getObjectKey();
                    record.setResizeUrl(ossServiceContext.getObjectUrl(OssConfiguration.bucket, 
                            objectKey.substring(0, objectKey.indexOf(".")) + "_resize"
                            + objectKey.substring(objectKey.indexOf("."))));
                } else {
                    record.setResizeUrl(ossServiceContext.getObjectUrl(OssConfiguration.bucket, record.getObjectKey(),
                            OssProcessEnum.RESIZE.getStyle()));
                }
                record.setOriginUrl(ossServiceContext.getObjectUrl(OssConfiguration.bucket, record.getObjectKey()));
                return record;
            }, threadPoolExecutor);
            futureList.add(future);
        });
        futureList.forEach(future -> listData.add(future.join()));
        return listData;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值