Хук выключения не убивает исполнителя

У меня есть следующий код:

public class Driver {
    private ExecutorService executor = Executors.newCachedThreadPool();

    public static void main(String[] args) {
        Driver d = new Driver();
        d.run();
    }

    private void run() {
        final Timer timer = new Timer();
        final TimerTask task = new TimerTask() {
            @Override
            public void run() {
                System.out.println("Task is running!");
            }
        };

        Runnable worker = new Runnable() {
            @Override
            public void run() {
                timer.scheduleAtFixedRate(task, new Date(), 5 * 1000);
            }
        };

        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                System.out.println("Shutdown hook is being invoked!");

                try {
                    if(executor.awaitTermination(20, TimeUnit.SECONDS))
                        System.out.println("All workers shutdown properly.");
                    else {
                        System.out.println(String.format("Maximum time limit of %s reached " +
                                "when trying to shut down workers. Forcing shutdown.", 20));
                        executor.shutdownNow();
                    }
                } catch (InterruptedException interrupt) {
                    System.out.println("Shutdown hook interrupted by exception: " +
                            interrupt.getMessage());
                }

                System.out.println("Shutdown hook is finished!");
            }
        });

        executor.submit(worker);

        System.out.println("Initializing shutdown...");
    }
}

Когда это запускается, я получаю следующий вывод консоли:

Initializing shutdown...
Task is running!
Task is running!
Task is running!
Task is running!
Task is running!
Task is running!
Task is running!
... (this keeps going non-stop)

Когда я запускаю это, приложение никогда не завершается. Вместо этого каждые 5 секунд я вижу новую печать «Задача выполняется!». Я бы ожидал, что основной поток достигнет конца метода main, напечатает "Инициализация завершения работы...", вызовет добавленный хук завершения работы, уничтожит исполнителя и, наконец, выведет "Хук завершения работы является законченный!".

Вместо этого «Задача выполняется» просто продолжает печататься, и программа никогда не завершается. Что тут происходит?


person Community    schedule 05.07.2013    source источник
comment
Похоже, у @Izik Golan есть решение вашей проблемы. Если это работает для вас, сделайте +1 и примите его ответ.   -  person zEro    schedule 08.07.2013


Ответы (1)


Он не закрывается, потому что Timer() создает и запускает поток, не являющийся демоном... который затем никогда не останавливается.

Есть две вещи, которые могут привести к самопроизвольному отключению JVM:

  • Звонок System.exit() (или Runtime.halt())
  • Завершение последнего оставшегося потока, не являющегося демоном.

Поскольку вы создали второй поток, не являющийся демоном (в дополнение к потоку, в котором выполняется main()), второе условие не будет выполнено.

person Stephen C    schedule 05.07.2013
comment
Спасибо @Stephen C (+1) - так какое здесь решение: сделать Timer демоном? Если да, то как? - person ; 05.07.2013
comment
@TicketMonster Используйте Timer(true) создать демон Timer. - person Jeffrey; 05.07.2013
comment
Еще раз спасибо @Stephen C, однако установка Timer(true) не приводит к отключению executor после завершения основного потока... - person ; 05.07.2013
comment
@TicketMonster - Вы говорите, что симптомы такие же, как и у Timer(true)? - person Stephen C; 06.07.2013