Поймать Ctrl+C в Java

Можно ли перехватить сигнал Ctrl+C в приложении командной строки Java? Я хотел бы очистить некоторые ресурсы перед завершением программы.

2 ответа

Решение

Вы можете прикрепить к виртуальной машине крюк отключения, который запускается всякий раз, когда виртуальная машина выключается:

Виртуальная машина Java отключается в ответ на два вида событий:

  • Программа завершается нормально, когда завершается последний поток, не являющийся демоном, или когда вызывается метод exit (эквивалентно System.exit), или

  • Виртуальная машина завершает работу в ответ на пользовательское прерывание, такое как нажатие клавиш Ctrl+C, или общесистемное событие, такое как выход пользователя из системы или завершение работы системы.

Тем не менее, поток, который вы передаете как ловушка завершения работы, должен следовать нескольким правилам, поэтому внимательно прочитайте связанную документацию, чтобы избежать проблем. Это включает обеспечение безопасности нити, быстрое завершение нити и т. Д.

Кроме того, как отмечает комментатор Джеспер, перехватчики завершения работы гарантированно работают при нормальном завершении работы виртуальной машины, но если процесс виртуальной машины завершается принудительно, они этого не делают. Это может произойти, если нативный код испортил или вы принудительно убили процесс (kill -9, taskkill /f).

Но в этих сценариях все ставки в любом случае отменены, поэтому я бы не стал тратить на это слишком много времени.

Просто для быстрого тестирования консоли...

Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
            try {
                Thread.sleep(200);
                System.out.println("Shouting down ...");
                //some cleaning up code...

            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    });

Верхний ответ предлагает использовать крючок отключения. Крючки отключения доставляют гораздо больше хлопот, чем они того стоят. Они работают в неопределенном порядке, и библиотеки, от которых вы зависите, могут добавлять свои собственные хуки выключения, что может означать, что кое-что, от чего зависит ваша собственная ловушка выключения, может быть деинициализировано до того, как будет запущена ваша ловушка выключения. Избавьте себя от головной боли и воспользуйтесь обработчиком сигналов:

Signal.handle(new Signal("INT"),  // SIGINT
    signal -> System.out.println("Interrupted by Ctrl+C"));

Signal Сейчас sun.misc.Signal, что означает, что он будет устаревшим, но то, чем он заменяется, в настоящее время называется jdk.internal.misc.Signal, поэтому, пока команда Java не выяснит, как публично раскрыть обработчики сигналов не внутренним способом, помните, что этот вызов может исчезнуть. На данный момент (по состоянию на JDK 11) sun.misc.Signal все еще существует.

Другие вопросы по тегам