finally block in daemon thread
I know that finally blocks in deamon threads would not be executed. But my meticulous nature tries to understand why and what happens in JVM so special that it could not call the code under this block. 开发者_Python百科
I think that it somehow related to call stack that it whould not unwind, but don't know how. Can someone please shed some light on this. Thanks.
Who says that finally
blocks in daemon threads don't execute? This is not true in general.
What you might have heard that a finally
block is not guaranteed to be executed when a JVM is shut down during the execution of the try
(or catch
) block. That is correct (and it can easily happen to daemon threads).
But again: during normal operation, there is nothing that stops finally
blocks from executing normally in daemon threads: they are not handled differently.
The shutdown problem is easy: when the JVM is asked to shut down or even forced to shut down, then it may simply not be able to execute any more statements.
For example, on POSIX-y operating systems, signal 9 (SIGKILL) forces an application to quit, giving it no chance to do any cleanup (this is why signal 15 (SIGTERM) is preferred, usually). In this case, the JVM can't execute the finally
block, because the OS won't let it run any longer.
If the JVM exits while the try or catch code is being executed, then the finally block may not execute.
Normal Shutdown - this occurs either when the last non-daemon thread exits OR when Runtime.exit()
When a thread exits, the JVM performs an inventory of running threads, and if the only threads that are left are daemon threads, it initiates an orderly shutdown. When the JVM halts, any remaining daemon threads are abandoned finally blocks are not executed, stacks are not unwound the JVM just exits. Daemon threads should be used sparingly few processing activities can be safely abandoned at any time with no cleanup. In particular, it is dangerous to use daemon threads for tasks that might perform any sort of I/O. Daemon threads are best saved for "housekeeping" tasks, such as a background thread that periodically removes expired entries from an in-memory cache.
Last non-daemon thread exits example:
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.");
}
}
Output:
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
I have created two non-daemon threads which will terminate before the rest two daemon threads.
One non-daemon thread wait for 20 sec, one daemon thread wait for 40 sec, one non-daemon thread sleep for 15 sec, one daemon thread sleep for 30 sec, one daemon thread sleep for 10 sec. The idea to terminate non-daemon threads before some daemon ones.
As the result suggests, the JVM will terminate as soon as there is no non-daemon thread alive, without executing the rest statements in the Runnable tasks of the daemon threads, even if they are inside finally block without throwing 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();
}
}
精彩评论