假设我对以下函数进行了几次调用:
public void StartTimedRuns(){
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask(){
public void run(){
//do something that takes less than a minute
}
}, 0, 60*1000);
}
我的理解是此时会有一堆线程同时运行。 也就是说,每个计时器实例将以1分钟的间隔生成短期线程。
假设按照此处的说明安装了一个关闭钩子(按下Control-C时运行):
关闭挂钩将取消所有计时器。 (假设我将计时器存储在类级别集合中)
我可以保证在VM退出之前所有活动线程都会运行完毕吗?
与此相关,只有在线程全部退出时才会调用shutdown hook吗?
答案 0 :(得分:5)
当主线程完成或通过Ctrl + C发生键盘中断时,将调用shutdown hook。
如果要保证活动线程将运行完成,则必须在shutdown hook中显式join()
它们。这有点棘手,因为TimerTask
使用的线程没有直接暴露给你,但是你可以在你的类中加入类似的东西:
private static List<Thread> timerThreads = new LinkedList<Thread>();
然后在TimerTask.run()
方法的最顶端出现类似的内容:
timerThreads.add(Thread.currentThread());
然后在关闭钩子中这样的事情:
try {
for (Thread t : timerThreads) {
t.join();
}
} catch (InterruptedException e) {
// handle it somehow
}
这可以保证所有活动线程都将运行完成。然而,这不一定是个好主意。引用the API documentation:
关闭挂钩在虚拟生命周期的微妙时间运行 机器,因此应该进行防御性编码。他们应该在 特别是,写成线程安全并避免死锁 尽可能的。 [...] 关机挂钩也应该完成他们的 工作很快。当程序调用{{1}}时,期望就是那样 虚拟机将立即关闭并退出。当虚拟 机器因用户注销或系统关闭而终止 底层操作系统可能只允许一段固定的时间 哪个关闭并退出。因此,不宜尝试 任何用户交互或执行长时间运行的计算 关机钩。