【问题标题】:Detect Ctrl+C in Java Console在 Java 控制台中检测 Ctrl+C
【发布时间】:2020-09-01 09:37:13
【问题描述】:

我有一个控制台-Java 游戏。如果按下Ctrl+C,游戏得分将保存在 JSON 文件中。将分数保存在 JSON 文件中的过程有效。但我不知道,如何从控制台检测Ctrl+C,如果发生这种情况,我会保存分数(只是一个方法调用)。 使用 KeyListener 它不能在控制台上工作(据我所知,只有 JFrame)。

我在互联网上找不到解决问题的方法。

我必须使用 Runtime 吗?我试过了,还是不行……

Runtime.getRuntime().addShutdownHook(new Thread()
{
    public void run()
    {
        Test.mainThread.interrupt();
    }
});

Stackoverflow 上有类似的问题,但不适用于控制台Catching Ctrl+C in Java

【问题讨论】:

  • 也许这个答案会对你有所帮助:stackoverflow.com/questions/18037576/…
  • 我试过了,但是没用请详细点。你的关机钩子没有运行吗?它运行但抛出异常了吗?它是否无一例外地运行,但没有按照您的意愿运行?
  • 没有任何效果,甚至没有消息。但我也不知道该怎么做......但我会看看来自@KrzysztofCichocki 的链接

标签: java command-line-interface control-c


【解决方案1】:

添加关闭挂钩是正确的方法,但Test.mainThread.interrupt(); 可能不起作用。 JVM 已经关闭。您的 mainThread 不太可能有时间响应中断;一旦所有关闭挂钩完成,Java 就会终止。

只需让您的关闭挂钩明确执行您需要采取的任何操作:

Runtime.getRuntime().addShutdownHook(new Thread()
{
    @Override
    public void run()
    {
        try
        {
            Test.saveScore();
        }
        catch (IOException e)
        {
            System.err.println("Couldn't save score before terminating.");
            e.printStackTrace();
        }
    }
});

【讨论】:

  • 这里是java.lang.Runtime类中方法addShutdownHook()javadoc的摘录: 在极少数情况下,虚拟机可能会中止,即停止运行没有干净地关闭。当虚拟机在外部终止时会发生这种情况,例如在 Unix 上使用 SIGKILL 信号或在 Microsoft Windows 上使用 TerminateProcess 调用。 ... 如果虚拟机中止,则无法保证是否会运行任何关闭挂钩。 Ctrl+C 在 Windows 上不会调用 TerminateProcess 吗?如果是这样,那么关闭挂钩很可能不会运行。
  • @Abra This Microsoft pagethis Java technical documentation 似乎暗示 Ctrl-C 可以被拦截和处理。
  • @VGR Test.mainThread.saveScore(); 是什么意思? Test 是类,在这个类中我必须抛出一个名为 mainThread? 的异常
  • @SwissCodeMen saveScore() 就是一个例子。无论您希望Test.mainThread.interrupt(); 产生什么效果,都必须将其移至Test(或其他类)中的单独方法,以便您可以显式调用它。中断一个线程不太可能有效。
  • 所以在这个 try-catch 块中,我只是调用了保存游戏的方法......但我在控制台中出现以下错误消息:Exception in thread "main" java.util.NoSuchElementException: No line found@VGR
【解决方案2】:

我们知道 CTRL-C 关闭应用程序并关闭 JVM。由于它是正常关机,它运行shutdown hooks。所以创建shutdown hook是正确的做法:

Runtime.getRuntime().addShutdownHook(new Thread(() -> {
    // Do something to save the score 
}));

请注意,我们在这里传递了 Runnable 作为关闭任务。所以我们可以传递一个具有所需功能的对象:

Runtime.getRuntime().addShutdownHook(new Thread(() -> {
    gameScores.save(); // assuming we have a gameScores object in this scope
}));

您通过中断线程的初始尝试可以被视为这种方法的一种变体。我们可以传递线程以稍后中断它,而不是传递业务对象 - gameScores。但最好还是在业务层面进行操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-14
    • 1970-01-01
    • 2015-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-08
    相关资源
    最近更新 更多