Ловіння Ctrl + C на Java


80

Чи можна вловити сигнал Ctrl+ Cу програмі командного рядка Java? Я хотів би очистити деякі ресурси перед тим, як припинити програму.

Відповіді:


89

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

Віртуальна машина Java вимикається у відповідь на два види подій:

  • Програма виходить нормально, коли виходить останній недемон-потік або коли викликається метод виходу (еквівалентно System.exit), або

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

Потік, який ви передаєте як гачок відключення, повинен дотримуватися кількох правил, тому уважно читайте пов'язану документацію, щоб уникнути проблем. Сюди входить забезпечення безпеки ниток, швидкого закінчення нитки тощо.

Крім того, як зазначає коментатор Джеспер, гачки відключення гарантовано працюють при нормальному відключенні ВМ, але якщо процес ВМ припиняється примусово, вони цього не роблять. Це може статися, якщо рідний код випсується або якщо ви примусово вб'єте процес ( kill -9, taskkill /f).

Але в цих сценаріях усі ставки в будь-якому випадку не діють, тому я б не надто витрачав на це думки.


1
Слідкуйте, щоб гачки відключення не гарантувались за будь-яких обставин; можуть траплятись ситуації, коли вони не запускаються, тому не робіть правильним функціонування вашої програми залежно від того, що ви робите під час відключення.
Jesper

4
Вони не запускаються, коли процес закінчується примусово ( TerminateProcess()або SIGKILL), але це поза нормальною роботою, і оскільки Ctrl + C вже охоплений гачком відключення, використовувати його можна безпечно. Ви багато не можете зробити, якщо ОС у будь-якому випадку фактично припиняє ваш процес.
Joey

1
kill -HUPє "найм'якшим" вбивством від Unix і має запустити гачок відключення. Не впевнений у замовчуванні kill.
livefree75

1
Вбивство за замовчуванням призводить до запуску гачка відключення на моїй машині (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();
            }
        }
    });

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все ще існує.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.