I am going to make the bold assumption that when the run method completes, the
Java virtual machine sets the target reference in the Thread object to null.
Here is what is happening:
Thread-1 object has a target variable that refers to the Runnable subclass object.
Thread-2 object has a target variable that refers to the Thread-1 object.
Thread-1 is started.
Thread-2 is started.
The JVM invokes thread1.run() which invokes target.run(). The JVM executes the run method of the Runnable object. When run() completes, the JVM sets the target variable in Thread1 to null.
The JVM invokes thread2.run() which would invoke target.run(), except the target is null. Instead thread2.run() returns.
*If* you add Thread.sleep(1000) to the run method, then what happens instead is, while Thread1 is sleeping, the JVM invokes thread2.run() which invokes target.run(). The JVM executes the run method of Thread1 which invokes its target.run(). The JVM executes the run method of the Runnable object.
It is also possible to explain the output when the starts are reversed. Try it!