Подтвердить что ты не робот

Как JVM завершает потоки демона? или Как написать потоки демона, которые заканчиваются изящно

Гипотетический сценарий:
У меня есть поток демона, ответственный за некоторый io, главный поток заканчивается и возвращается, а JVM решает прервать поток моего демона.

Как это сделать? Прерывание? Доработка? Как я могу закодировать свой поток демона, чтобы он изящно реагировал при завершении?

4b9b3361

Ответ 1

Я просто написал следующий код в качестве теста:

public class DaemonThreadPlay {
    public static void main(String [] args) {
        Thread daemonThread = new Thread() {
            public void run() {
                while (true) {
                    try {
                        System.out.println("Try block executed");
                        Thread.sleep(1000l);
                    } catch (Throwable t) {
                        t.printStackTrace();
                    }
                }
            }

            @Override
            public void finalize() {
                System.out.println("Finalize method called");
            }
        };
        daemonThread.setDaemon(true);
        daemonThread.start();

        try {
            Thread.sleep(2500l);
        } catch (Throwable t) {
            //NO-OP
        }
    }
}    

Я установил точки останова в блоке catch потока daemon и в методе finalize. Ни одна точка останова не была достигнута, даже если блок try был выполнен. Очевидно, что этот код имеет проблемы синхронизации/синхронизации, но я думаю, что мы можем с уверенностью заключить, что потоки демона не прерываются при выключении, и их методы finalize() не вызываются.

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

Thread shutdownHook = ... // construct thread that somehow
                          // knows about all the daemon threads
Runtime.getRuntime().addShutdownHook(shutdownHook);

Завершение выключения может, очевидно, выполнять любые задачи, необходимые для "изящного" выключения.

Ответ 2

Я думаю, вы неправильно поняли, что такое поток демона.

Смотрите что представляет собой поток демона в java

В общем, это в основном означает, что поток демона не должен делать ввода-вывода или содержать какие-либо ресурсы. Если вы нарушаете это основное правило, то ваш поток не может считаться потоком демона.

Добавление запирающего крюка - это стандартный способ обеспечения того, чтобы ваш код вызывался до завершения JVM, но даже это не гарантировано на 100%. Например, ваша JVM может быть повреждена, оставив ОС убирать ресурсы таким образом, чтобы защищает ОС, но, скорее всего, оставляет ваше приложение в несогласованном/ошибочном состоянии.

Системные контрольные точки и механизмы восстановления возвращаются к ранним дням программного обеспечения (например, операционные системы и пакетные операции), и, к сожалению, это колесо продолжает заново изобретаться, поскольку нет подхода "серебряной пули" (API), который решает эту проблему проблемы в достаточно общем роде.

Ответ 3

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

ExecutorService execPool = Executors.newSingleThreadExecutor(new ThreadFactory() {

    @Override    
    public Thread newThread(Runnable runnable) {       
         Thread thread = Executors.defaultThreadFactory().newThread(runnable);
         thread.setDaemon(true);
         return thread;    
    } 
}); 

вызывать метод shutdown executorservice из выключения.

Runtime.getRuntime().addShutdownHook(....)

Ответ 4

использовать прерывание и присоединиться:

class Daemon extends Thread {
    public void run() {
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                System.out.println(e);
                break;
            }
        }
        System.out.println("exit run()");
    }
}   
public class So8663107 {
    public static void main(String[] arguments) throws InterruptedException {
        System.out.println(Thread.activeCount());
        Daemon daemon = new Daemon();
        daemon.setDaemon(true);
        daemon.start();
        Thread.sleep(2500);
        System.out.println(Thread.activeCount());
        daemon.interrupt();
        daemon.join();
        System.out.println(Thread.activeCount());
    }
}