ExecutorService 关闭
1、shutdown
2、shutdownNow
3、awaitTermination
当你使用ExecutorService
的时候,你应该记得关闭它,这样这些被管理的线程才会停止运行。
举例:如果你的应用通过main()方法启动,并且你的 应用中存在一个 激活的 ExecutorService,那么即使你的main thread
(main线程)已经退出了,这个应用依然会在后台运行。 原因: ExecutorService
中的活跃线程,防止了jvm关闭ExecutorService
。
结论:jvm是可能无法关闭ExecutorService
的,如果某些情况下,你不希望ExecutorService
在后台不受控制的执行,那你在必要的时候 需要手动调用 ExecutorService
中的shutdown
方法。
手动调用shutdown并不会立即关闭ExecutorService,而是等待ExecutorService中所有的任务完成,并且提交之后,才会关闭的。
这个方法会平滑地关闭ExecutorService,当我们调用这个方法时,ExecutorService停止接受任何新的任务且等待已经提交的任务执行完成(已经提交的任务会分两类:一类是已经在执行的,另一类是还没有开始执行的),当所有已经提交的任务执行完毕后将会关闭ExecutorService。
awaitTermination判断执行的状态,如果执行时间过长就调用shutdownNow 方法立即中止执行。
public static void shutdownAndAwaitTermination(int awaitTime, ExecutorService pool) {
pool.shutdown(); //禁用提交的新任务
try {
if (!pool.awaitTermination(awaitTime, TimeUnit.SECONDS)) {
pool.shutdownNow();
}
} catch (InterruptedException e) {
pool.shutdownNow(); //(重新)取消当前线程是否中断
Thread.currentThread().interrupt(); //保持中断状态
}
}
参考:
[翻译][Java]ExecutorService的正确关闭方法(有Demo)
深入理解在Android中线程池的使用 (shutdown那部分 有出入,作者给予了反馈感谢,牵扯的方面很多,循循渐进,点赞)
android多线程之三:终止线程池的方法(分析很透彻)
-------------------------------------------------------------------------------------
如何判断线程池中任务执行完毕
这里用到的是给用户提供反馈,判断多个异步操作执行完毕的结果。
CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程执行完后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有框架服务之后执行。
CountDownLatch是通过一个计数器来实现的,计数器的初始化值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就相应得减1。当计数器到达0时,表示所有的线程都已完成任务,然后在闭锁上等待的线程就可以恢复执行任务。
public class Test1 {
public static ExecutorService executorService = Executors.newCachedThreadPool();
private static CountDownLatch cdl = new CountDownLatch(10);
private static final Random random = new Random();
public void test() {
for (int i = 0; i < 10; i++) executorService.execute(new ThreadTest());
}
public static void main(String[] args) {
new Test1().test();
//插入数据完成后 执行修改操作
try {
cdl.await();
} catch (InterruptedException e) {
}
System.out.println("它们已经插完啦..............................");
executorService.shutdown();
}
class ThreadTest implements Runnable {
public void run() {
//执行插入数据操作 每次插入一条
// 模拟耗时
int time = random.nextInt(10000);
try {
Thread.sleep(time);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName() + "执行完了,耗时:" + time / 1000 + "秒");
cdl.countDown();
}
}
}
参考: