Future异步任务

CompletableFuture实现了CompletableStage接口和Future接口,前者是对后者的一个扩展,增加了异步回调、流式处理、多个Future组合处理的能力,使Java在处理多任务的协同工作时更加顺畅便利。

先看一下传统线程池执行异步线程,获取线程处理结果的方式。

public static void main(String[] args) throws Exception {
    // 创建异步执行任务:
    ExecutorService executorService= Executors.newSingleThreadExecutor();
    Future<String> childThread = executorService.submit(()->{
        System.out.println(Thread.currentThread()+" start,time->"+System.currentTimeMillis());
        Thread.sleep(2000);
        System.out.println(Thread.currentThread()+" exit,time->"+System.currentTimeMillis());
        return "子线程结束";
    });
    System.out.println("main thread start,time->"+System.currentTimeMillis());
    //等待子任务执行完成,如果已完成则直接返回结果
    System.out.println("child thread result->"+childThread.get());
    System.out.println("main thread exit,time->"+System.currentTimeMillis());
    executorService.shutdown();
}

执行结果如下
在这里插入图片描述
子线程是异步执行的,主线程休眠等待子线程执行完成,子线程执行完成后唤醒主线程,主线程获取任务执行结果后退出。
很多博客说使用不带等待时间限制的get方法时,如果子线程执行异常了会导致主线程长期阻塞,这其实是错误的,子线程执行异常时其异常会被捕获,然后修改任务的状态为异常结束并唤醒等待的主线程,get方法判断任务状态发生变更,就终止等待了,并抛出异常。这时主线程拿到抛出的异常,如果没做特殊处理,则同样会抛出异常终止程序,而不是一直阻塞在那里。
在这里插入图片描述
通过源码也可以看出,get方法会对异步线程的状态进行判断,获取线程结果并抛出线程中的异常。
将代码改造如下

public static void main(String[] args) throws Exception {
    // 创建异步执行任务:
    ExecutorService executorService= Executors.newSingleThreadExecutor();
    Future<String> childThread = executorService.submit(()->{
        System.out.println(Thread.currentThread()+" start,time->"+System.currentTimeMillis());
        Thread.sleep(2000);
        if(true){
            throw new Exception("抛出异常咯");
        }
        System.out.println(Thread.currentThread()+" exit,time->"+System.currentTimeMillis());
        return "子线程结束";
    });
    System.out.println("main thread start,time->"+System.currentTimeMillis());
    //等待子任务执行完成,如果已完成则直接返回结果
    //如果执行任务异常,则get方法会把之前捕获的异常重新抛出
    try{
        System.out.println("child thread result->"+childThread.get());
    }catch (Exception e){
        throw e;
    }finally {
        executorService.shutdown();
    }
    System.out.println("main thread exit,time->"+System.currentTimeMillis());
}

执行结果如下
在这里插入图片描述
这里解释一下为什么要catch住之后再抛出,这样做的目的是为了在finally中shutdown线程池。
线程池内部有一个类似于死循环的方法,这个循环是非守护线程(用户线程),而JVM对于非守护线程,如果不终止的话,程序是不会结束的,main方法就是非守护线程。
所以如果不shutdown线程池,main方法即使因为抛出异常而结束了,但你会发现程序任然在运行,如下所示(将finally中的语句注释掉即可得到下面的运行结果)
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值