Thread vs Daemon
There is a fundamental difference between JVM thread and daemon. The easiest way to see it, is by reading Oracle's documentation regarding method setDaemon in Thread class. Let's see what JavaDoc says:
There is a fundamental difference between JVM thread and daemon. The easiest way to see it, is by reading Oracle's documentation regarding method setDaemon in Thread class. Let's see what JavaDoc says:
" (setDaemon method) Marks this thread as either a daemon thread or a user thread. The Java Virtual Machine exits when the only threads running are all daemon threads."
I guess is pretty obvious. When there are no 'user threads' or simply threads, spawned by a given JVM, JVM exits.
Finally block
However there is one more gotcha there. It is the problem of finally block execution. Now, let's analyze Oracle's documentation devoted to finally block:
"The
Just below that general definition, there is an interesting note:
"Note: If the JVM exits while the
finally
block always executes when the try
block exits. This ensures that the finally
block is executed even if an unexpected exception occurs. But finally
is useful for more than just exception handling — it allows the programmer to avoid having cleanup code accidentally bypassed by a return
, continue
, or break
. Putting cleanup code in a finally
block is always a good practice, even when no exceptions are anticipated."Just below that general definition, there is an interesting note:
"Note: If the JVM exits while the
try
or catch
code is being executed, then the finally
block may not execute. Likewise, if the thread executing the try
or catch
code is interrupted or killed, the finally
block may not execute even though the application as a whole continues."
Nice. I think, I am getting slightly confused, now. Moreover, Oracle gives another important note, at the end of the page, saying that finally block prevents from resource leaks:
"Important: The
finally
block is a key tool for preventing resource leaks. When closing a file or otherwise recovering resources, place the code in a finally
block to ensure that resource is always recovered."Question
So my question is, how finally block behaves, when daemon and thread are interrupted?
Experiment
Experiment
I prepared two, fairly simple examples. There is a SampleProcess class, which is intended to be run in background i.e. that is what newly spawned thread or daemon will do. It will be kicked off by the ProcessLauncher object from either ThreadRunner or DaemonRunner runner classes.
package common; public class SampleProcess { public void start() { try { System.out.println("Sample process is going to sleep."); sleep(5000); } finally { sleep(1500); System.out.println("Sample process is running finally block."); } } private void sleep(long timeToSleep) { try { Thread.sleep(timeToSleep); } catch (InterruptedException e1) { System.out.println("Sample process is running catch block for time to sleep = " + timeToSleep); } } }
package common; public class ProcessLauncher { public void launchAsThread() { this.launch("Thread", false); } public void launchAsDaemon() { this.launch("Daemon", true); } private void launch(String processName, boolean isDaemon) { Thread process = new Thread(){ @Override public void run() { new SampleProcess().start(); } }; process.setDaemon(isDaemon); process.start(); System.out.println(processName + " runner is going to interrupt sample process."); process.interrupt(); } }
package daemon; import common.ProcessLauncher; public class DaemonRunner { public static void main(String[] args) { new ProcessLauncher().launchAsDaemon(); } }
package thread; import common.ProcessLauncher; public class ThreadRunner { public static void main(String[] args) { new ProcessLauncher().launchAsThread(); } }
Results
And here are results for thread and daemon, respectively:
Thread runner is going to interrupt sample process. Sample process is going to sleep. Sample process is running catch block for time to sleep = 5000 Sample process is running finally block. Process finished with exit code 0
Daemon runner is going to interrupt sample process. Sample process is going to sleep. Sample process is running catch block for time to sleep = 5000 Process finished with exit code 0
Conclusion
The important conclusion is fact that daemon processes are somewhat unsafe and misleading. They DO NOT ALWAYS run finally block, which prevents us from resource leaks. So, when JVM halts, it only waits for 'user threads' to be finished. Any remaining daemon threads are simply stopped. Finally blocks are not run - JVM just stops.
That is why, daemon threads should be used with at most care and prudence. Also, bear in mind that using daemons for tasks related to resource management (I/O) is walking on a thin ice.
You can find entire example on my GitHub account.
The important conclusion is fact that daemon processes are somewhat unsafe and misleading. They DO NOT ALWAYS run finally block, which prevents us from resource leaks. So, when JVM halts, it only waits for 'user threads' to be finished. Any remaining daemon threads are simply stopped. Finally blocks are not run - JVM just stops.
That is why, daemon threads should be used with at most care and prudence. Also, bear in mind that using daemons for tasks related to resource management (I/O) is walking on a thin ice.
You can find entire example on my GitHub account.
No comments:
Post a Comment