Как изящно обрабатывать сигнал SIGTERM в Java?

Предположим, у нас есть такой тривиальный демон, написанный на java:

public class Hellow {
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        while(true) {
            // 1. do
            // 2. some
            // 3. important
            // 4. job
            // 5. sleep
        }

    }
}

и мы демонизируем его, используя start-stop-daemon, который по умолчанию отправляет сигнал SIGTERM (TERM) на --stop

Предположим, текущий выполненный шаг — №2. И в этот самый момент мы посылаем сигнал TERM.

Что происходит, так это то, что выполнение немедленно прекращается.

Я обнаружил, что могу обработать сигнальное событие с помощью addShutdownHook(), но дело в том, что оно все равно прерывает текущее выполнение и передает управление обработчику:

public class Hellow {
    private static boolean shutdownFlag = false;
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        registerShutdownHook();

        try {
            doProcessing();
        } catch (InterruptedException ex) {
            System.out.println(ex);
        }
    }

    static private void doProcessing() throws InterruptedException {
        int i = 0;
        while(shutdownFlag == false) {
            i++;
            System.out.println("i:" + i);
            if(i == 5) {
                System.out.println("i is 5");
                System.exit(1); // for testing
            }

            System.out.println("Hello"); // It doesn't print after System.exit(1);

            Thread.sleep(1000);
        }
    }

    static public void setShutdownProcess() {
        shutdownFlag = true;
    }

    private static void registerShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread() {
            public void run() {
                System.out.println("Tralala");
                Hellow.setShutdownProcess();
            }
        });
    }
}

Итак, мой вопрос: можно ли не прерывать текущее выполнение, а обрабатывать сигнал TERM в отдельном потоке (?), чтобы я мог установить shutdown_flag = True, чтобы цикл в main имел возможность изящно остановиться?


person Islomkhodja Hamidullakhodjaev    schedule 18.11.2017    source источник


Ответы (2)


Я переписал метод registerShutdownHook() и теперь он работает так, как я хотел.

private static void registerShutdownHook() {
    final Thread mainThread = Thread.currentThread();
    Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
            try {
                System.out.println("Tralala");
                Hellow.setShutdownProcess();
                mainThread.join();
            } catch (InterruptedException ex) {
                System.out.println(ex);
            }

        }
    });  
}
person Islomkhodja Hamidullakhodjaev    schedule 23.11.2017

Вы можете использовать SignalHandler. Посмотрите этот пример: https://dumpz.org/2707213/.

Он поймает сигнал INTERRUPTED и сбросит флаг operating, что, в свою очередь, позволит корректно закрыть приложение.

введите здесь описание изображения

person Beastmaster    schedule 20.11.2017
comment
Да, ваше решение работает, но при компиляции компилятор ругается, что SignalHandler в будущем не работает. Я нашел другое решение, но спасибо) - person Islomkhodja Hamidullakhodjaev; 23.11.2017
comment
@IslomkhodjaHamidullakhojaev Не могли бы вы поделиться своим решением? С уважением - person Jorge Lavín; 14.11.2019