наконец, блок в потоке демона - PullRequest
8 голосов
/ 18 июля 2011

Я знаю, что, наконец, блоки в потоках deamon не будут выполняться. Но моя дотошная натура пытается понять, почему и что происходит в JVM, настолько особенном, что он не может вызвать код в этом блоке.

Я думаю, что это как-то связано со стеком вызовов, что он не должен раскручиваться, но не знаю как. Может кто-нибудь, пожалуйста, пролить свет на это. Спасибо.

Ответы [ 3 ]

11 голосов
/ 18 июля 2011

Кто сказал, что блоки finally в потоках демона не выполняются?Это не в общем случае.

То, что вы могли бы слышали, что не гарантируется выполнение блока finally, когда JVM выключается во времявыполнение блока try (или catch).Это правильно (и это может легко случиться с потоками демона).

Но опять же: при нормальной работе ничто не мешает finally блокам нормально выполняться в потоках демона: они не обрабатываются по-разному.

Проблема выключения проста: когда JVM просят выключить или даже принудительно завершить работу, он может просто не в состоянии выполнить еще какие-либо операторы.

Например, в операционных системах POSIX-y сигнал 9 (SIGKILL) заставляет закрыть приложение, не давая ему никакой возможности выполнить очистку (этоименно поэтому сигнал 15 (SIGTERM) является предпочтительным, обычно).В этом случае JVM не может выполнить блок finally, поскольку ОС больше не позволяет ему работать.

2 голосов
/ 14 июля 2012

Я создал два потока, не являющихся демонами, которые завершатся раньше, чем остальные два потока демонов.

Один поток, не являющийся демоном, ожидает в течение 20 секунд, один поток демона ожидает 40 секунд, один поток, не являющийся демономсон в течение 15 секунд, один поток демона спит в течение 30 секунд, один поток демона спит в течение 10 секунд.Идея завершить потоки, не являющиеся демонами, перед некоторыми демонами.

Как следует из результата, JVM завершит работу, как только не останется живого потока, не являющегося демоном, без выполнения операторов rest в задачах Runnableпотоки демона, даже если они находятся внутри блока finally, не генерируют исключение InterruptedException.

public class DeamonTest {

    public static void main(String[] args) {
        spawn(40000, Action.wait, true);
        spawn(30000, Action.sleep, true);
        spawn(10000, Action.sleep, true);
        spawn(20000, Action.wait, false);
        spawn(15000, Action.sleep, false);
    }

    enum Action {
        wait, sleep
    }

    private static void spawn(final long time, final Action action,
                              boolean daemon) {
        final Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {

                    Thread thread = Thread.currentThread();
                    try {
                        switch (action) {
                        case wait: {
                            synchronized (this) {

                                System.out.println(thread + " daemon="
                                                   + thread.isDaemon() + ": waiting");
                                wait(time);
                            }
                            break;
                        }
                        case sleep: {

                            System.out.println(thread + " daemon="
                                               + thread.isDaemon() + ": sleeping");
                            Thread.sleep(time);
                        }
                        }
                        System.out.println(thread + " daemon=" + thread.isDaemon()
                                           + ": exiting");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        System.out.println(thread + " daemon=" + thread.isDaemon()
                                           + ": finally exiting");
                    }
                }

            });
        thread.setDaemon(daemon);
        thread.start();
    }
}
2 голосов
/ 08 сентября 2011

Если JVM завершает работу во время выполнения кода try или catch, блок finally может не выполняться.
Нормальное отключение - это происходит либо при последнем потоке, не являющемся демономвыходит из режима ИЛИ, когда Runtime.exit ()
При выходе из потока JVM выполняет инвентаризацию запущенных потоков, и если единственные оставшиеся потоки являются потоками демона, он инициирует упорядоченное завершение работы.Когда JVM останавливается, все оставшиеся потоки демона прекращаются, и, наконец, блоки не выполняются, стеки не свернуты, JVM просто завершается.Потоки демонов следует использовать экономно, но некоторые операции обработки можно безопасно отменить в любое время без очистки.В частности, опасно использовать потоки демона для задач, которые могут выполнять любые операции ввода-вывода.Потоки демона лучше всего сохранять для выполнения «служебных» задач, таких как фоновый поток, который периодически удаляет просроченные записи из кэша в памяти.

Последний выход из потока, не являющегося демоном, пример:

public class TestDaemon {
    private static Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                while (true) {
                    System.out.println("Is alive");
                    Thread.sleep(10);
                    // throw new RuntimeException();
                }
            } catch (Throwable t) {
                t.printStackTrace();
            } finally {
                System.out.println("This will never be executed.");
            }
        }
    };

    public static void main(String[] args) throws InterruptedException {
        Thread daemon = new Thread(runnable);
        daemon.setDaemon(true);
        daemon.start();
        Thread.sleep(100);
        // daemon.stop();
        System.out.println("Last non-daemon thread exits.");
    }
}

Вывод:

Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Last non-daemon thread exits.
Is alive
Is alive
Is alive
Is alive
Is alive
...