【发布时间】:2013-07-18 15:48:00
【问题描述】:
我刚刚遇到了一个有趣的问题。似乎,在 Java 中,如果一个线程调用System.exit(),则它不能通过Thread.join() 加入。
这引起了我的问题,因为我想在我的应用程序之后使用关闭挂钩进行清理,例如:
Runtime.getRuntime.addShutdownHook(new Thread() {
public void run() {
reader.join();
writer.join();
in.close();
out.close();
}
});
这个想法是确保线程在关闭这些资源之前已经完成了它们各自的资源。问题是有 3 种情况可以调用关闭挂钩。它们是:
- 用户点击 [ctrl] + [C]。
- Reader 线程完成,并调用
System.exit()。 - 编写器线程完成,并调用
System.exit()。
第一种情况,用户点击 [ctrl] + [C] 可以正常工作。但在其他两种情况下,关闭挂钩会永远阻塞。这是一个连锁效应,即一个 Thread.join()(针对已调用 System.exit() 的线程调用)永远阻塞。
因此,我有 2 个问题。首先,我知道我可以改用Thread.join(long millis),这样他们就不会无限期地阻塞,但是谁能想到一个更优雅的解决方案?其次,虽然可以对同一个线程调用Thread.join() 两次,而第二次它会立即返回,有没有人知道为什么对已经调用System.exit() 的线程调用Thread.join() 会无限期阻塞并且不会'不只是立即返回?
【问题讨论】:
-
为什么不尽量避免调用
System.exit(),而是安排适当的清理,让JVM自然退出? -
还要注意“如果
System.exit()在虚拟机开始关机序列后被调用,那么如果关机钩子正在运行,这个方法将无限期地阻塞。” - 做你打电话给System.exit()两次? (Reference)
标签: java multithreading sigint shutdown-hook