Java控制台程序按下Ctrl+C时如何终止进程?
解决Ctrl+C退出控制台循环的问题
原代码里的try-catch没法处理Ctrl+C的中断——按下Ctrl+C会直接触发JVM的终止信号,不会让scanner.nextLine()抛出普通异常,所以得换个方式实现,核心是拦截中断信号+用标志位控制循环,具体如下:
解决步骤与代码
核心思路
- 用
volatile修饰布尔变量做中断标志,保证信号处理器和主线程之间的变量可见性 - 注册信号处理器或关闭钩子,捕获Ctrl+C触发的终止信号,修改标志位
- 把死循环改成基于标志位的循环,让程序优雅退出
- 用try-with-resources自动管理文件流和输入流,避免资源泄漏
修改后的代码(兼容Java 8及以下)
import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.List; import java.util.Scanner; import sun.misc.Signal; import sun.misc.SignalHandler; public class YourConsoleApp { // volatile保证多线程下变量可见性 private static volatile boolean stopFlag = false; public static void concatenation(List<String> commands) throws IOException { // 注册SIGINT信号处理器(对应Ctrl+C) Signal.handle(new Signal("INT"), signal -> { stopFlag = true; System.out.println("\nInterrupted. Stopping..."); }); if (commands.get(1).equals(">")) { String path = history.getFilePath(); File file = new File(path + "\\" + commands.get(2)); if (file.exists() && file.isFile()) { // try-with-resources自动关闭writer和scanner try (FileWriter writer = new FileWriter(file); Scanner scanner = new Scanner(System.in)) { System.out.println("Write to file. Press Ctrl+C to stop."); String line; while (!stopFlag) { if (scanner.hasNextLine()) { line = scanner.nextLine(); writer.write(line + System.lineSeparator()); writer.flush(); } // 短暂休眠减少CPU空轮询 try { Thread.sleep(100); } catch (InterruptedException e) { stopFlag = true; } } } catch (IOException e) { System.out.println("Error writing to file: " + e.getMessage()); } } } else { System.out.println("bash : " + commands.get(1) + " : unrecognized operator"); } } }
Java 9+兼容方案
如果用Java 9及以上,sun.misc.Signal属于内部API可能被限制访问,可以改用JVM关闭钩子实现:
// 替换信号处理器的注册代码,改用ShutdownHook Runtime.getRuntime().addShutdownHook(new Thread(() -> { stopFlag = true; System.out.println("\nInterrupted. Stopping..."); }));
关键说明
- volatile变量:
stopFlag必须加volatile,因为信号处理器/关闭钩子是在独立线程中修改变量,volatile能确保主线程立刻读到最新值,不会因为线程缓存导致循环无法退出。 - 循环控制:把
while(true)改成while(!stopFlag),当收到中断信号时,标志位变为true,循环自动终止。 - 资源管理:用try-with-resources包裹
FileWriter和Scanner,JVM会在代码块结束时自动关闭资源,不用手动调用close()。 - 避免空轮询:添加
Thread.sleep(100),减少循环空转对CPU的消耗。
内容的提问来源于stack exchange,提问作者Sanjay Kumar
相关产品推荐
相关产品推荐

