3
votes

In the below code:

class Worker extends Thread {
    Thread t;

    public Worker(Thread thread) {
        t=thread;
    }

    public void run() {
        try {
            t.join();
        } catch(InterruptedException e) {
            System.out.println("Exception is thrown and caught");
        }
        System.out.println(Thread.activeCount());
        System.out.print("|work|");
    }

    public static void main(String[] args) {
        Thread t=Thread.currentThread();
        Worker worker = new Worker(t);
        worker.setDaemon(true);
        worker.start();
        System.out.println("Exit from main method");
    }
}

Since worker is a daemon thread joined on main() thread, |work| should never be printed since the user thread main() completes first, and since worker is a daemon thread it too is stopped when the main() thread dies. But, the output I get is as follows : Exit from main method 1 |work|

Please clarify this query for me.

After many many executions of the program, I have observed the following different outputs:

without Thread.sleep(1000) :

Exit from main method 2

Exit from main method 1 |work|

Exit from main method 2 |work|

with Thread.sleep(1000) :

Exit from main method 2 |work|

Exit from main method

Notice the first output without sleep() method. |work| is not printed but the thread count is shown to be 2. Does this mean main() thread execution ended after Thread.activeCount() but before |work| is printed? In third output seems like main() ended after execution of both these statements.

Now, I was never expecting Thread.activeCount() to be 2, since the daemon thread worker is joined on user thread main(), which means when Thread.activeCount() is executed, there will only be worker thread and no main() thread.

3
I thought the point of daemon threads was that they're safely "cut-loose"; that they aren't required to be joined. - Carcigenicate
Did the InterruptedException happen? - user207421
No. It did not. The program terminated normally after printing |work| - paidedly
How do you know? With that code, you cannot possibly tell. You have an empty catch block for that exception. - user207421
Your program will exit when all non-daemon threads are done executing. You said t.start() and also a Sysout immediately after. I'd think that your main() exits even before the t.join happens or some sort of scheduling happens which makes your Sysout execute before the join call. Can you execute it a few times ( a lot ) and see what if your behavior changes? Also add a sleep after the t.start() and before the sysout and see what happens? - Praba

3 Answers

2
votes

I don't know the exact details on how the VM knows when the last non-daemon thread stops running, but I can imagine 2 solutions:

  • a background regularly polls to see if all non-daemon threads have exited (and I doubt that's the actual solution)
  • a background thread joins on all the non-deamon threads, and exits the VM once all the join return

In those two situations, a race condition is possible, and the daemon thread sometimes has time to execute a few more operations after the main thread has died, and sometimes not.

I executed your code a few times, and sometimes something is printed after the main thread has exited, and sometimes not, which corroborates my theory.

When I add a Thread.sleep(100L) call after t.join(), nothing is printed except "Exit from main method".

Also note that if you look at the list of threads running in the VM (using the debugger for example), one of them is named "DestroyJavaVM". Given the name, I'd guess this is the thread which exits the JVM, concurrently to the remaining daemon threads, once the last non-daemon thread stops running.

0
votes

How do you run your code?

When I run your example from command line I am getting: Exit from main method 1 |work|

I guess you might not get activeCount and |work| printed out as JVM can just stop daemon-threads when all non-daemon threads terminated (the only one here is main thread). When that condition is met, JVM terminates remaining daemon threads and exits.

Thread javadoc says:

The Java Virtual Machine continues to execute threads until either of the following occurs:

  • The exit method of class Runtime has been called and the security manager has permitted the exit operation to take place.
  • All threads that are not daemon threads have died, either by returning from the call to the run method or by throwing an exception that propagates beyond the run method.

Terminating those threads might take some time though, so your daemon thread might have a chance to execute some more instructions. When I add Thread.sleep(1000) after printing activeCount, the activeCount is still printed, but |work| is not.

0
votes

Let me first attempt to answer the outputs for

without Thread.sleep(1000)

Exit from main method 2 - You have to remember your Worker thread is a daemon so the JVM is not going to wait for it to complete its execution. It is only bothered about completing the main thread execution which is a non daemon. Now you are getting this output because "Exit from Main Method" was shown by the main thread and in the meantime worker thread ran and displayed 2 but alas unfortunately the main thread completed and the JVM did not wait for the worker thread ( being a daemon) hence 'work' was not displayed.

Exit from main method 1 |work| - Here go with the same explanation as above B U T the worker thread was lucky ..it got enough time to display '|work|' before the JVM completed the main thread and hurried to its exit.

Exit from main method 2 |work| - Same as previous explanation...not sure about why active count returns 2 sometimes and 1 sometimes.

You could use similar logic for coming to conclusions for the

With Thread.sleep(1000) logic.

Tip: Also you can check the status of thread t with statement System.out.println("status of t : " + t.getState()); just before t.join()....you will get TERMINATED a lot..which proves that the main thread which is the NON DAEMON has already terminated so no question of join working... too late...