I understand that T1, after starting T2, has to obtain T2's lock, so has to synch with T2, and then get on T2's waiting list by calling T2's wait() method.
But what confuses me is, why would the run() method in T2 have to synch with "this", which is like synching with itself, to call notify()? All I know is if I do not synch with "this", then I'll get a runtime exception (IllegalMonitorStateException).
So, please correct me if I'm wrong, to call notify(), a thread has to obtain it's own lock? If so, why?
There are two ways to answer this...
The simple answer is that it is a requirement of the API. You need to own the lock of the object that you are using to wait() or notify() with.
The really complex answer is because there is an inherent race condition related to wait() and notify().
You should not be using wait() and notify(), by itself, without some sort of flag. If you do, there will be cases where notifications will get lost.
Unfortunately, there is no way to protect the flag without integrating the freeing of the synchronization lock into the wait() method. This is why wait() mandates that the lock be owned. And for completion, since you are supposed to manage the lock anyway, notify() also mandates it.
This leads to another question. If I know the simple reason, and only grab the lock because the API mandates it, but don't know anything about the race condition, is it possible that I could get wait() and notify() to compile correctly, but the program won't be working?
Unfortunately, the answer is yes. You should spend some time with the Sun tutorial on threads, to fully understand wait() and notify().
Henry