1

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

 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

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

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

与此相关,关闭钩子是否仅在线程全部退出时才被调用?

4

1 回答 1

5

当主线程完成或通过 Ctrl+C 发生键盘中断时,将调用关闭挂钩。

如果要保证活动线程将运行完成,则必须join()在关闭挂钩中显式地显示它们。这有点棘手,因为TimerTasks 使用的线程不会直接暴露给你,但你可以在你的类中放置这样的东西:

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,期望虚拟机将立即关闭并退出。当虚拟机由于用户注销或系统关闭而终止时,底层操作系统可能只允许关闭和退出的固定时间量。因此,不建议尝试任何用户交互或在关闭挂钩中执行长时间运行的计算。

于 2012-01-09T10:21:46.133 回答