如果VM被Control-C关闭,我可以确保我的定时器启动线程运行完成吗?

mer*_*011 1 java command-line control-c java-6

假设我对以下函数进行了几次调用:

 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);
 }
Run Code Online (Sandbox Code Playgroud)

我的理解是,此时会有一堆线程同时运行.也就是说,每个计时器实例将以1分钟的间隔生成短期线程.

假设我按照以下说明安装了一个关闭钩子(按下Control-C时运行):

在Java中捕获Ctrl + C.

关闭挂钩将取消所有计时器.(假设我将计时器存储在类级别的集合中)

我可以保证在VM退出之前所有活动线程都将运行完成吗?

与此相关,只有在线程全部退出时才会调用shutdown钩子吗?

Tay*_*mon 5

当主线程完成或通过Ctrl + C发生键盘中断时,将调用shutdown hook.

如果要保证活动线程将运行完成,则必须join()在shutdown hook中明确它们.这有点棘手,因为TimerTasks 使用的线程并没有直接暴露给你,但你可以在你的类中放置这样的东西:

private static List<Thread> timerThreads = new LinkedList<Thread>();
Run Code Online (Sandbox Code Playgroud)

然后在TimerTask.run()方法的最顶端这样的事情:

timerThreads.add(Thread.currentThread());
Run Code Online (Sandbox Code Playgroud)

然后在关闭钩子中这样的事情:

try {
    for (Thread t : timerThreads) {
        t.join();
    }
} catch (InterruptedException e) {
    // handle it somehow
}
Run Code Online (Sandbox Code Playgroud)

这可以保证所有活动线程都将运行完成.然而,这不一定是个好主意.引用API文档:

关闭挂钩在虚拟机的生命周期中的微妙时间运行,因此应该进行防御性编码.特别是它们应该被编写为线程安全的并且尽可能避免死锁.[...]关机挂钩也应该快速完成工作.当程序调用exit期望时,虚拟机将立即关闭并退出.当虚拟机因用户注销或系统关闭而终止时,底层操作系统可能只允许一段固定的时间来关闭和退出.因此,不建议尝试任何用户交互或在关闭钩子中执行长时间运行的计算.