Как JVM завершает потоки демона? или Как написать потоки демона, которые заканчиваются изящно
Гипотетический сценарий:
У меня есть поток демона, ответственный за некоторый io, главный поток заканчивается и возвращается, а JVM решает прервать поток моего демона.
Как это сделать? Прерывание? Доработка? Как я могу закодировать свой поток демона, чтобы он изящно реагировал при завершении?
Ответы
Ответ 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());
}
}