假设我对以下函数进行了几个调用:
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时运行):
在Java 中捕获Ctrl+C
关机挂钩将取消所有计时器。(假设我将计时器存储在类级集合中)
我可以保证在虚拟机退出之前,所有活动线程都将运行完成吗?
与此相关的是,关闭挂钩是否只有在线程全部退出时才会被调用?
当主线程完成或通过Ctrl+C发生键盘中断时,会调用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
}
这保证了所有活动线程都将运行到完成。然而,这不一定是个好主意。引用API文件:
关机挂钩在虚拟机生命周期中的一个微妙时刻运行机器,因此应该进行防御编码。他们应该在特别是,编写时要确保线程安全并避免死锁尽可能[…]关闭挂钩也应该完成它们的快速工作。当程序调用
exit
时,预期是虚拟机将立即关闭并退出。当虚拟由于用户注销或系统关闭,计算机被终止底层操作系统可能只允许在关闭并退出。因此,尝试是不可取的任何用户交互或在关机挂钩。