如何在 finally 块中调用 System.exit(0) 后运行代码

Posted

技术标签:

【中文标题】如何在 finally 块中调用 System.exit(0) 后运行代码【英文标题】:How to run code after a call to Sytem.exit(0) in a finally block 【发布时间】: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 类的实际功能进行太多更改。

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

【问题讨论】:

Preventing System.exit() from API 的可能重复项 【参考方案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

【讨论】:

以上是关于如何在 finally 块中调用 System.exit(0) 后运行代码的主要内容,如果未能解决你的问题,请参考以下文章

JAVA语言如何进行异常处理,关键字throws,throw,try,catch,finally分别代表啥意义在try块中抛出异常吗

JAVA 语言如何进行异常处理,关键字: throws,throw,try,catch,finally分别代表什么意义? 在try块中可以抛 出异常吗?

Try-catch-finally-return 澄清 [重复]

在 finally 块中抛出异常

Java中final关键字如何使用?

Java中final关键字如何使用?