4

我刚刚遇到了一个有趣的问题。似乎,如果在 Java 中,一个线程调用System.exit()它就不能通过Thread.join().

这引起了我的问题,因为我想在我的应用程序之后使用关闭挂钩进行清理,例如:

Runtime.getRuntime.addShutdownHook(new Thread() {
    public void run() {
        reader.join();
        writer.join();
        in.close();
        out.close();
    }
});

这个想法是它确保线程在关闭这些资源之前已经完成了它们各自的资源。问题是有 3 种情况可以调用关闭挂钩。他们是:

  1. 用户点击 [ctrl] + [C]。
  2. 阅读器线程完成,并调用System.exit().
  3. Writer 线程完成,并调用System.exit().

第一种情况,用户点击 [ctrl] + [C] 可以正常工作。但在其他两种情况下,关闭挂钩会永远阻塞。这是一个连锁效应,Thread.join()即针对已经调用过的线程调用的oneSystem.exit()永远阻塞。

因此,我有 2 个问题。首先,我知道我可以改用Thread.join(long millis)它们,这样它们就不会无限期地阻塞,但是谁能想到一个更优雅的解决方案?其次,虽然一个人可以调用Thread.join()同一个线程两次,而第二次它会立即返回,有没有人知道为什么调用Thread.join()一个已经System.exit()无限期调用块并且不立即返回的线程的原因?

4

4 回答 4

2

System.exit如果成功即使通过抛出异常也不会返回,所以线程永远不会完成。在关闭挂钩之前,这不是问题。

解决方法是使用通常的标准锁(甚至只是用 破解它new Thread(new Runnable() { public void run() { System.exit(0); }}).start();)。

于 2013-07-18T16:01:52.690 回答
1

您正在做的事情是特别禁止的:

关闭挂钩也应该快速完成它们的工作。

加入随机线程不能被描述为“快速”。

显然,这些线程在退出时应该关闭自己的流如果他们不退出,调用将如何join()完成任何事情?

于 2013-07-19T00:04:03.687 回答
0

不建议使用 System.exit() ,因为它只会终止 JVM。还有其他并发工具,例如 CountDownLatch。您甚至可以使用 finally 在关机时正确清理。

于 2013-07-18T15:52:53.300 回答
0

使用执行器,不要使用连接或手动创建线程。

在 java.util.concurrent 中使用 executor 和其他东西时,您可以简单地调用 shutdown 并等待它终止、指定超时等。更加健壮。如果您使用的是 java 1.7,请使用 try with resources 来关闭您的流。这样,除了关闭执行程序之外,您没有太多清理工作要做。如果没有,请使用 finally 块。永远不要在 finally 块之外的任何地方调用 close。

于 2013-07-18T16:35:07.247 回答