我刚遇到一个有趣的问题。看来,如果在Java中,一个线程调用System.exit()
,那么它就不能通过Thread.join()
加入。
这导致了我的问题,因为我想在我的应用程序之后使用关闭钩子来清理,例如:
Runtime.getRuntime.addShutdownHook(new Thread() {
public void run() {
reader.join();
writer.join();
in.close();
out.close();
}
});
这个想法是,在关闭这些资源之前,它确保线程已完成各自的资源。问题是有3种情况可以调用关闭钩子。他们是:
System.exit()
。System.exit()
。用户点击[ctrl] + [C]的第一种情况正常。但在其他两种情况中,关闭挂钩永远阻塞。这是一个事实的连锁效应,即一个Thread.join()
,一个已经调用System.exit()
的线程被调用,永远阻止。
因此,我有两个问题。首先,我知道我可以使用Thread.join(long millis)
代替它们,以便它们不会无限期地阻止,但任何人都可以想到更优雅的解决方案吗?其次,虽然可以两次针对同一个线程调用Thread.join()
,但是第二次它会立即返回,有没有人知道为什么调用Thread.join()
针对已调用{{1}的线程的原因无限制地阻止而不仅仅立即返回?
答案 0 :(得分:2)
System.exit
如果成功,即使通过抛出异常也不返回,所以线程永远不会完成。这在关闭钩子之前不是问题。
解决方法是使用通常的标准锁(甚至只使用new Thread(new Runnable() { public void run() { System.exit(0); }}).start();
进行破解)。
答案 1 :(得分:1)
您正在做的是specifically prohibited:
关机挂钩也应该快速完成工作。
加入随机线程不能被描述为“快速”。
显然,这些线程在退出时应关闭其自己的流。如果他们不退出,调用join()
将如何完成任何事情?
答案 2 :(得分:0)
不建议使用System.exit(),因为它只是终止JVM。还有其他并发工具,如CountDownLatch。您甚至可以在关机时使用finally来正确清理。
答案 3 :(得分:0)
使用执行程序,不要使用join或手动创建线程。
当使用执行程序和java.util.concurrent中的其他内容时,您可以简单地调用shutdown并等待它终止,指定超时等等。更加健壮。如果您使用的是java 1.7,请使用try with resources来关闭您的流。这样,除了关闭执行程序之外,您没有太多的清理工作。如果没有,请使用finally块。永远不要在最后一个街区以外的任何地方打电话。