CompletableFuture,使用

前言

  1. jdk1.8前,使用future获取结果的情况比较多,但是这种使用方式有个缺点,就是调用future.get()的时候会阻塞主线程,如果第一个任务的future.get()一直阻塞,那么后面的结果也就一直被阻塞了。因此从1.8开始可以使用CompletableFuture去实现,多线程异步执行任务,并且在主线程最终等待所有的任务返回结果。达到多线程处理的目的。

一、代码示例

  public static void main(String[] args) {
        // 1.新建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        // 2.存放异步返回结果
        List<Integer> result = new ArrayList<>();
        // 3.存放需要互相等待的异步线程的resultfuture
        CompletableFuture<Integer> [] resultFuture = new CompletableFuture[2];
        //4. 这里模拟了两个线程任务,计算1+1=2 并且返回结果
        CompletableFuture<Integer> resultFuture1 = CompletableFuture.supplyAsync(() -> {
            return 1 + 1;
        },executorService).whenComplete((r,t)->{
            result.add(r);
        });

        resultFuture[0]=resultFuture1;
        //5.执行第二个线程任务2+2=4,并且等待执行结果
        CompletableFuture<Integer> resultFuture2 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 2 + 2;
        }).whenComplete((r, t) -> {
            result.add(r);
        });
        resultFuture[1]=resultFuture2;

        //6.需要相互等待的线程
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.allOf(resultFuture);
        long begin = System.currentTimeMillis();
        // 7.开始阻塞获取结果
        voidCompletableFuture.join();
        // 8记录耗时
        System.out.println("耗时:"+(System.currentTimeMillis()-begin));
        // 9.输出结果
        for (Integer temp: result) {
            System.out.println("结果:"+temp);
        }
        // 10.关掉线程池,不关掉,main方法会一直运行。
        executorService.shutdown();
    }

运行结果截图如下:
![在这里插入图片描述](https://img-blog.csdnimg.cn/dd55c44ce3ec4003b55629c8f8fc1a59.png


总结

1.这里需要说明的是异步线程CompletableFuture.allOf方法仅支持可变参数类型,也就是这里是不能放list结果的,这里需要使用数组去存放需要等待结果的线程future。
2.CompletableFuture 如果是有返回值使用supplyAsync,如果是没有返回值的执行runAsync使用上都差不多就不做示例了。
3.CompletableFuture 执行上面的两个方法的时候可以自己传入线程池,也可以不传入线程池,如果不传入线程池,则使用的是forkjoin生成的comonpool去执行,这种线程池需要多核cup才能发挥优势,不过现在基本没有服务器是单核了吧,这个了解下就行。
4.还有线程池最好是自己通过new ThreadPoolExecutor创建,而不是和我一样,我只是为了快速写代码偷懒,例如使用本实例的方式创建线程池,缺点就是线程池的队列最大值是int的最大值,意味着可以放非常多的线程,这就有可能导致内存溢出如果线程非常多的时候。这是不严谨的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值