ExecutorService 退出

如果ExecutorService中的任务运行完毕之后,ExecutorService不会自动关闭。它会等待接收新的任务。当你是使用完ExecutorService后,你应该关闭它,使得线程不能持续运行。

例如,你的应用程序从main()方法开始并且你的主线程退出应用程序,这时如果存在激活状态的ExecutorService,你的应用程序将仍然会保持运行。ExecutorService中激活的线程会阻止JVM关闭。

如果需要关闭ExecutorService, 我们需要调用shutdown() 或者 shutdownNow()方法。

为了终止ExecutorService中的线程,你需要调用shutdown()方法。ExecutorService不会立即关闭,但是它也不会接受新的任务,直到它里面的所有线程都执行完毕,ExecutorService才会关闭。所有提交到ExecutorService中的任务会在调用shutdown()方法之前被执行。

如果你想立即关闭ExecutorService,你可以调用shutdownNow()方法。这将会尝试立即停止所有正在执行的任务,并且忽略所有提交的但未被处理的任务。对于正在执行的任务是不能确定的,也许它们停止了,也行它们执行直到结束。

方法说明

shutdown()

停止接收新任务,原来的任务继续执行

英文原意:关闭,倒闭;停工。 这里的意思是 关闭线程池与使用数据库连接池一样,每次使用完毕后,都要关闭线程池。

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

shutdown() 会立即销毁ExecutorService,它会让ExecutorServic停止接收新的任务,并等待现有任务全部执行完毕再销毁。

  1. executorService.shutdown();

shutdownNow()

停止接收新任务,原来的任务停止执行

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

说明:它试图终止线程的方法是通过调用 Thread.interrupt() 方法来实现的,这种方法的作用有限,如果线程中没有sleep 、wait、Condition、定时锁等应用, interrupt() 方法是无法中断当前的线程的。所以,shutdownNow() 并不代表线程池就一定立即就能退出,它也可能必须要等待所有正在执行的任务都执行完成了才能退出。但是大多数时候是能立即退出的。

shutdownNow()并不保证所有的任务都被执行完毕,它会返回一个未执行任务的列表:

  1. List<Runnable> notExecutedTasks = executorService.shutdownNow();

awaitTermination(long timeOut, TimeUnit unit)

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

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

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

oracle推荐的最佳关闭方法是和awaitTermination一起使用:

  1. executorService.shutdown();
  2. try {
  3. if (!executorService.awaitTermination(800, TimeUnit.MILLISECONDS)) {
  4. executorService.shutdownNow();
  5. }
  6. } catch (InterruptedException e) {
  7. executorService.shutdownNow();
  8. }

先停止接收任务,然后再等待一定的时间让所有的任务都执行完毕,如果超过了给定的时间,则立刻结束任务。

比较

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

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

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

shutdown() 后,不能再提交新的任务进去;但是 awaitTermination() 后,可以继续提交。

awaitTermination()是阻塞的,返回结果是线程池是否已停止(true/false);shutdown() 不阻塞。

总结

1、优雅的关闭,用 shutdown()

2、想立马关闭,并得到未执行任务列表,用shutdownNow()

3、优雅的关闭,并允许关闭声明后新任务能提交,用 awaitTermination()

4、关闭功能 【从强到弱】 依次是:shuntdownNow() > shutdown() > awaitTermination()