栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Future异步任务

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Future异步任务

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

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

public static void main(String[] args) throws Exception {
    // 创建异步执行任务:
    ExecutorService executorService= Executors.newSingleThreadExecutor();
    Future 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 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中的语句注释掉即可得到下面的运行结果)

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/835996.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号