我知道最终不会执行守护线程中的块。但是我一丝不苟的天性试图理解为什么 JVM 会发生什么以及发生了什么如此特别以至于它无法调用此块下的代码。
我认为它与调用堆栈有关,它不会展开,但不知道如何。有人可以对此有所了解。谢谢。
谁说finally
守护线程中的块不执行?一般情况下这是不正确的。
您可能听说过,在执行(or ) 块finally
期间关闭 JVM 时,不能保证执行块。这是正确的(它很容易发生在守护线程上)。try
catch
但同样:在正常操作期间,没有什么可以阻止finally
块在守护线程中正常执行:它们的处理方式不同。
关闭问题很简单:当要求 JVM 关闭甚至强制关闭时,它可能根本无法执行更多语句。
例如,在 POSIX-y 操作系统上,信号 9 (SIGKILL)强制应用程序退出,使其没有机会进行任何清理(这就是为什么通常首选信号 15 (SIGTERM) 的原因)。在这种情况下,JVM无法执行该finally
块,因为操作系统不会让它继续运行。
如果在执行 try 或 catch 代码时 JVM 退出,则 finally 块可能不会执行。
正常关闭 - 这发生在最后一个非守护线程退出或 Runtime.exit() 时
当线程退出时,JVM 会清点正在运行的线程,如果剩下的唯一线程是守护线程,它会启动有序关闭。当 JVM 停止时,任何剩余的守护线程都被放弃,finally 块不执行,堆栈不展开,JVM 就退出。应该谨慎使用守护线程,很少有处理活动可以随时安全地放弃而无需清理。特别是,将守护线程用于可能执行任何类型 I/O 的任务是很危险的。守护线程最好保存用于“管家”任务,例如定期从内存缓存中删除过期条目的后台线程。
最后一个非守护线程退出示例:
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
我创建了两个非守护线程,它们将在其余两个守护线程之前终止。
一个非守护线程等待 20 秒,一个守护线程等待 40 秒,一个非守护线程休眠 15 秒,一个守护线程休眠 30 秒,一个守护线程休眠 10 秒。在一些守护线程之前终止非守护线程的想法。
结果表明,只要没有非守护线程处于活动状态,JVM 就会终止,而不执行守护线程的 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();
}
}