Ooohhhh I like this one. Good one Marcus!
He never does start any threads, so in fact the *only* threads that are running are those started by the JVM. As far as *you* are concerned, there is only one thread and thus one call stack -- main.
So here's what happens:
1) He makes an instance of Pmcraven, passing a name "one" to its constructor. At this point, it's just a plain old object on the heap like every other object. No special "threadness". This is how all threads start their life.
2) He invokes the run() method on that object. Doesn't matter if that method were the foo() method or the go() method or anything else. There is nothing special about run(), as a method name, unless you really DO start a thread, in which case, the thread then knows that the first method to call is run().
3) So, you're always free to call run() on a Thread instance yourself. But that means you get a plain old Thread object's run() method, but you don't get any *threadness*. In other words, you don't get a shiny new call stack. Here's the key...
4) The run() method in this example is called from the *main* thread, rather than from the new thread that would have been created if he had called start() on the Thread instance.
5) So what about yield() and sleep()? Well, remember what those methods do. They are static methods of class Thread. But what do they do? They sleep() or yield() THE CURRENTLY RUNNING THREAD. In other words, the *main* thread.
6) To put it into a timeline...
1) instance one is created and put on the heap
2) instance one has its run() method invoked.
3) the run() method begins, and starts a loop.
4) the run() method encounters a sleep() call. This puts the main thread to sleep! Because main is the currently running thread, main goes to sleep.
5) There is no chance for the other Thread instance to be created, because the call stack is frozen at that sleep() call. So the scheduler selects another thread to run, like the garbage collector.
6) the sleep timer expires, and the *main* thread returns to runnable. The scheduler picks it again, and then it hits a yield() call, which probably has NO affect at all since main is almost certainly the highest priority thread.
7) finally, the System.out println prints the name.
8) the loop isn't finished, so it starts again and does the whole thing I just described, ending with printing "one" again.
9) the run() method completes, and is popped off the main call stack.
10) Now we move to the next line of code in the main() method, which instantiates the second Thread instance and off we go...
Just remember:
- There is only ONE user-generated thread / call stack: main
- It is perfectly OK to call a Thread object's run() method, but this does not mean you will get an actual *thread of execution*.
- It is fine to call sleep() and yield() with a Thread instance, because they are inherited methods from Thread (static, but that's OK).
cheers,
Kathy
p.s. you can expect something vaguel similar on the real exam... something to see if you understand that calling a Thread object's run() does not make a new thread/call stack.