Good question. The comments in the JDK7 Object implementation shed some light on this, I think (emphasis mine):
This method causes the current thread (call it T
) to place
itself in the wait set for this object and then to relinquish any
and all synchronization claims on this object.
...
The thread T
is then removed from the wait set for this
usual manner with other threads for the right to synchronize on the
object; once it has gained control of the object, all its
synchronization claims on the object are restored to the status quo
ante - that is, to the situation as of the time that the wait
method was invoked. Thread T
then returns from the
invocation of the wait
method. Thus, on return from the
wait
method, the synchronization state of the object and of thread
T
is exactly as it was when the wait
method was
invoked.
So I think the first point to note is that wait()
doesn't return until the caller is done waiting (obviously). Meaning that if wait()
itself were synchronized then the caller would continue to hold the lock on the object, and nobody else would be able to wait()
or notify()
.
Now obviously wait()
is doing something tricky behind the scenes to force the caller to lose its ownership of the lock on the object anyways, but perhaps this trick would not work (or would be significantly more difficult to make work) if wait()
itself were synchronized.
The second point is that if multiple threads are waiting on an object, when notify()
is used to wake exactly one of them the standard contention method is used to allow only one thread to synchronize on the object, and that wait()
is supposed to restore the caller's synchronization claims to the exact state they were in prior to the call to wait()
. It seems possible to me that requiring the caller to hold the lock prior to calling wait()
simplifies this, as it removes the need to check to see if the caller should or should not continue holding the lock after wait()
returns. The contract stipulates that the caller must continue holding the lock, and thus some of the implementation is simplified.
Or perhaps it was simply done to avoid the appearance of the logical paradox of "if wait()
and notify()
are both synchronized, and wait()
doesn't return until notify()
is called, how can either ever be used successfully?".
Those are my thoughts, anyways.
notify()
on the lock when it is done, and the "Print" thread just callswait()
on the lock object when it starts, and prints "Download finished" once thewait()
returns. None of this strictly requires the addition of synchronized blocks in either thread. – Griseofulvin