若是优雅地关闭ExecutorService提供的java线程池

ExecutorService让咱们能够优雅地在程序中使用线程池来建立和管理线程,并且性能佳、开销小,还能够有效地控制最大并发线程数,是咱们在java并发编程中会常常使用到的。java

每个线程都会占用系统资源,所以线程池的关闭与清理一样重要,本文介绍咱们如何优雅地关闭线程池。web

一. ExecutorService中关闭线程池的方法

1. shutdown()

中止接收新任务,原来的任务继续执行编程

  1. 中止接收新的submit的任务;
  2. 已经提交的任务(包括正在跑的和队列中等待的),会继续执行完成;
  3. 等到第2步完成后,才真正中止;

2. shutdownNow()

中止接收新任务,原来的任务中止执行并发

  1. 跟 shutdown() 同样,先中止接收新submit的任务;
  2. 忽略队列里等待的任务;
  3. 尝试将正在执行的任务interrupt中断;
  4. 返回未执行的任务列表;

    说明:它试图终止线程的方法是经过调用 Thread.interrupt() 方法来实现的,这种方法的做用有限,若是线程中没有sleep 、wait、Condition、定时锁等应用, interrupt() 方法是没法中断当前的线程的。因此,shutdownNow() 并不表明线程池就必定当即就能退出,它也可能必需要等待全部正在执行的任务都执行完成了才能退出。可是大多数时候是能当即退出的。异步

3. awaitTermination(long timeOut, TimeUnit unit)

当前线程阻塞,timeout 和 TimeUnit 两个参数,用于设定超时的时间及单位,当前线程阻塞,直到:jvm

  • 等全部已提交的任务(包括正在跑的和队列中等待的)执行完;
  • 或者 等超时时间到了(timeout 和 TimeUnit设定的时间);
  • 或者 线程被中断,抛出InterruptedException

而后会监测 ExecutorService 是否已经关闭,返回true(shutdown请求后全部任务执行完毕)或false(已超时)ide

二. 三种方法的区别

1. shutdown() 和 shutdownNow() 的区别

  • shutdown() 只是关闭了提交通道,用submit()是无效的;而内部该怎么跑仍是怎么跑,跑完再停。
  • shutdownNow() 能当即中止线程池,正在跑的和正在等待的任务都停下了。

2. shutdown() 和 awaitTermination() 的区别

  • shutdown() 后,不能再提交新的任务进去;可是 awaitTermination() 后,能够继续提交。
  • awaitTermination() 是阻塞的,返回结果是线程池是否已中止(true/false);shutdown() 不阻塞。

3. 总结

  1. 优雅的关闭,用 shutdown()
  2. 想立马关闭,并获得未执行任务列表,用shutdownNow()
  3. 优雅的关闭,并容许关闭声明后新任务能提交,用 awaitTermination()
  4. 关闭功能 【从强到弱】 依次是:shuntdownNow() > shutdown() > awaitTermination()

三. RunTime.getRunTime().addShutdownHook()的做用

RunTime.getRunTime().addShutdownHook()的做用就是在JVM销毁前执行的最后一个线程,经过addShutdownHook添加钩子,当系统执行完这些钩子后,jvm才会关闭,所以咱们能够在这个线程中把咱们前面使用ExecutorService建立的线程池优雅地关闭掉。
在web3j中异步执行类(Async)中有以下代码:函数

// 建立线程池
private static final ExecutorService executor = Executors.newCachedThreadPool();

// 添加关闭线程池的钩子
static {
    Runtime.getRuntime().addShutdownHook(new Thread(() - > shutdown(executor)));
}

// 关闭线程池的钩子函数
private static void shutdown(ExecutorService executorService) {
    // 第一步:使新任务没法提交
    executorService.shutdown();
    try {
        // 第二步:等待未完成任务结束
        if(!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
             // 第三步:取消当前执行的任务
            executorService.shutdownNow();
            // 第四步:等待任务取消的响应
            if(!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
                System.err.println("Thread pool did not terminate");
            }
        }
    } catch(InterruptedException ie) {
        // 第五步:出现异常后,从新取消当前执行的任务
        executorService.shutdownNow();
        Thread.currentThread().interrupt(); // 设置本线程中断状态
    }
}
相关文章
相关标签/搜索