【问题标题】:How to run code after a call to Sytem.exit(0) in a finally block如何在 finally 块中调用 System.exit(0) 后运行代码
【发布时间】:2012-01-04 16:53:47
【问题描述】:

我有三个类,分别是 alpha、beta、gamma,这三个类中的每一个都有一个 main 方法。

alpha 和 beta 类在它们的 main 方法中都有一个 try...catch...finally 块,例如:

public class alpha{

    public static void main(String[] args){
        try{
            Do something;
        }catch(Exception ex){
            ex.printStackTrace();
        }
        finally{
            System.exit(0);
        }
    }
}


public class beta{

    public static void main(String[] args){
        try{
            Do something;
         }catch(Exception ex){
            ex.printStackTrace();
        }
        finally{
            System.exit(0);
        }
    }
}

现在在 gamma 类中,我调用 alpha 和 beta 类的主要方法来连续运行,如下所示

public gamma{

    public static void main(String[] args) {
        try {
            alpha.main(arg);
            beta.main(arg1);
        } catch (Exception e) {
            e.printStackTrace();
        }
}

问题在于,由于 alpha 类的 finally 块内的 System.exit(0),永远无法到达代码 beta.main(arg1)。 由于 alpha 和 beta 在单独执行时是独立的应用程序,因此它们应该在程序结束时终止服务。 所以现在有任何方法可以到达beta.main(arg1) 行,而不会对 alpha 和 beta 类的实际功能进行太多更改。

如果您需要更多详细信息,请告诉我。 提前谢谢...

【问题讨论】:

标签: java


【解决方案1】:

在这种情况下,可以使用关闭钩子:

public class Gamma{

    public static void main(String[] args) {
        try {
        Thread hook = new Thread() { public void run() { Beta.main(args); } };
            hook.setDaemon(true);
            Runtime.getRuntime().addShutdownHook(hook);
            Alpha.main(args);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

【讨论】:

  • 不错。我从来没有想过使用关闭挂钩作为延续机制。
  • 嗨弗拉德...我还有一个查询...当 alpha.main(args) 和 beta.main(args) 都执行时如何结束您的代码服务。??在此先感谢...
  • 您的程序执行得非常完美,就像我想要的那样,但只有一个问题是伽玛类应该在执行您的语法后结束服务(与 System.exit(0) 相同)。你能帮上忙吗……?谢谢...
  • 很好...我已经更新了代码。钩子线程应该是守护进程,不会阻塞最终的 System.exit(0)。
  • 嗨,弗拉德,感谢您的回复......即使将守护进程设置为 true,程序也不会终止。您的代码是否缺少某些内容..请帮帮我。谢谢...
【解决方案2】:

(理想情况下,作为模块公共 API 的一部分的任何东西都不应该做任何调用 exit 的事情,并且类的 main 方法应该只是一个小 shim,它调用之前完成实际工作的其他东西生成正确的退出代码。)

也就是说,如果您想阻止System.exit,您可以注册一个SecurityManager,它将对System.exit 的调用转换为SecurityExceptions 或Errors。

System.exit:

投掷

SecurityException - 如果存在安全管理器并且其checkExit 方法不允许以指定状态退出。

类似

System.setSecurityManager(new SecurityManager() {
  @Override
  public void checkExit(int exitCode) throws SecurityException {
    throw new SecurityException("stop that");
  }
});

然后调用主方法的方法可以捕获并抑制SecurityException。您可以通过创建自己的 ExitCalledError 并抛出它并仅抑制它来使其更健壮。

我发现这对于防止单元测试运行器在测试运行器被测试代码exited 且退出代码为零时虚假地报告成功非常有用。

【讨论】:

  • 嗯。我无法决定我对此的看法——我讨厌使用 SecurityManager 来做与安全无关的事情,但这是一种优雅的 hack。
  • @CharlieMartin,我同意这是一个 hack。不过,随着黑客攻击的进行,它相当强大,并且一些担忧,即测试运行者反馈的可靠性,保证了它的 IMO。当然也有问题——SecurityManager 的存在可能会引起库代码中的细微错误,并可能影响 VM 优化事物的方式。
  • 好吧,我赞成。不过我还没有决定我的想法。
【解决方案3】:

真的,唯一的解决方案是摆脱 System.exit() 调用。这就是为什么 System.exit() 是邪恶的。替换它们的一个好方法是抛出一个异常——你可以向系统添加一个异常处理程序(考虑将它们添加到 ThreadGroups 为每个异常路径添加一个),然后决定你想要做什么。

【讨论】:

    【解决方案4】:

    System.exit(0) 终止当前运行的 Java 虚拟机。它会关闭 VM 上的所有应用程序,而不仅仅是调用System.exit(0) 的应用程序。您需要为您的功能考虑替代方案。这是一个关于它的链接。 System.exit usage

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-01
      • 2021-06-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多