Java无限循环按Ctrl+C时try块语句重复执行原因排查
问题根本原因
首先要澄清一个常见误解:你在程序等待输入时按Ctrl+C触发NoSuchElementException,并不是JVM收到了进程终止信号(SIGINT)。默认配置下JVM收到SIGINT会直接终止进程,根本不会执行你写的catch块逻辑。你能走到异常分支,是因为终端在规范输入模式下,优先把Ctrl+C解释为「中断当前阻塞的读输入操作」,让System.in输入流返回中断/结束状态,而不是直接把信号发给JVM杀进程。
重复输出的核心诱因是两个逻辑问题叠加,既不是Java语言本身的机制缺陷,也不是Scanner类的bug:
- 第一,你写的
for(;;)是没有任何退出条件的无限循环,catch块里没有加break时,捕获异常、打印完退出提示后,程序根本不会终止,会立刻进入下一轮循环。 - 第二,Scanner在输入流被中断、到达EOF状态后,内部会标记「输入源已耗尽」,后续再调用
next()等读取方法时,不会再阻塞等待用户输入,会立刻抛出NoSuchElementException。
这两个问题叠加后,流程就变成了:
- 第一次按Ctrl+C,阻塞的
sc.next()被中断抛出异常,进入catch块打印第一遍退出提示 - 因为没有break,循环回到开头,先打印
Enter a word:,再调用sc.next() - 此时Scanner已经处于输入耗尽状态,立刻第二次抛出异常,进入catch块打印第二遍退出提示
- 上述流程会快速循环重复,直到输出缓冲区刷新、或者JVM真正被终止信号杀死,你就会看到2次甚至多次重复的打印内容。
你在catch块加上break之后,第一次捕获到异常就会直接跳出无限循环,main方法执行完程序正常退出,自然不会再触发后续的重复异常和打印,问题就消失了。
补充验证点:你可以在catch块里加一行打印异常堆栈的代码,会发现重复触发的异常栈完全一致,都是
sc.next()调用抛出的,不存在什么信号处理重复触发的问题。如果在程序没有等待输入的时机按Ctrl+C,JVM会直接收到SIGINT终止进程,根本不会执行你catch块里的打印逻辑。
内容的提问来源于stack exchange,提问作者imraklr
相关产品推荐
相关产品推荐

