Ловля Ctrl + C в Java

80

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

Пьер
источник

Ответы:

89

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

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

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

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

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

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

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

Джоуи
источник
1
Помните, что хуки выключения не гарантируются при любых обстоятельствах; могут быть ситуации, когда они не запускаются, поэтому не ставьте правильное функционирование вашей программы в зависимость от того, что вы делаете в ловушке завершения работы.
Джеспер,
4
Они не запускаются, когда процесс завершается принудительно ( TerminateProcess()или SIGKILL), но это выходит за рамки нормальной работы, и поскольку Ctrl + C уже охвачен ловушкой выключения, его можно безопасно использовать. Вы ничего не сможете сделать, если ОС все равно завершит ваш процесс.
Джои,
1
kill -HUPэто самое «мягкое» уничтожение из Unix, и оно должно запускать ловушку выключения. Не уверен насчет дефолта kill.
livefree75
1
По умолчанию kill запускает ловушку выключения на моей машине (Redhat 7.3). Убить -9 нельзя.
MikeKulls
2
Не гарантируется, что хуки выключения будут запускаться в каком-либо определенном порядке, поэтому, если ваша ловушка выключения полагается на другие не запущенные хуки выключения (или наоборот), вы можете столкнуться с проблемами.
Люк Хатчисон
28

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

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

            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                e.printStackTrace();
            }
        }
    });
Bkomac
источник
0

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

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все еще существует.

Люк Хатчисон
источник