The method wait should be called for an object only when the current thread (call it T) has already locked the object's lock. Suppose that thread T has in fact performed N lock actions that have not been matched by unlock actions. The wait method then adds the current thread to the wait set for the object, disables the current thread for thread scheduling purposes, and performs N unlock actions to relinquish the lock. The thread T then lies dormant until one of three things happens:
Now, I understand this business with N lock and N unlock actions, to mean that in the case that I hold multiple locks on the same object, an equal amount of unlock actions will occur when I call wait() on that object, in such a way that when wait() is called (no matter how many locks on that object I have gained), it will become "free (able to be locked by some other thread)" when I perform that single wait() on it. I also suppose that if I have gained the monitor control (however many "lock actions" that may be) on two (or in the general case, or more) separate objects, and I call wait() off of one of the object references, then I retain control of the other monitor, which practically means that if I call obj2.wait() when I have control of obj1 and obj2 locks, and I intend to be notify()d by another thread when obj2 reaches some state S, but the other thread needs to lock and perform some action on obj1 before notifying me, I will have deadlock (of at least those two threads involved). So I have two questions: 1: am I correct in assuming that no matter how many lock actions I perform on one object, a single wait() performed on that object (by the same thread, of course) will release the object so that other threads can lock it, and 2: that holding locks on multiple objects and then waiting on one of them will retain the locks on the others? Thanks, John
Originally posted by John Rushington: The JLS states that:
So I have two questions: 1: am I correct in assuming that no matter how many lock actions I perform on one object, a single wait() performed on that object (by the same thread, of course) will release the object so that other threads can lock it, and 2: that holding locks on multiple objects and then waiting on one of them will retain the locks on the others? Thanks, John
Hi John, It's important to make the distinction here between owning a lock and performing a lock action: you can't perform a lock action, it's done on your behalf. I suspect that you know this, based on the depth of your question, but I wanted to clear in our terminology. In the case of 1) Yes, you're absolutely correct. No matter how many locks a given thread has achieved on a given object, they are all released when wait successfully executes. Otherwise, no other synchronized thread could modify the object, and we know that this is not the case. 2) You're also right here. Obtaining a lock on a given object and releasing that lock has nothing to do with any other locks. A corollary to this is the fact that locking a given object does not lock the member variables of that object. This is easy enough to test in Java 1.4, which contains a holdsLock(Object) method on the Thread object. HTH, M, author The Sun Certified Java Developer Exam with J2SE 1.4
Then I suppose it would be correct to say that "The first successful lock action (done on your behalf by the VM, where a single lock action is equal to successfully entering a synchronized block or synchronized method, whether or not you already have performed a lock action on that object) corresponds to obtaining the lock on an object (and each object has associated with it a single lock). All "unlock actions" on a given object are performed with a single wait() call on that object"?
Yes, that's correct. After the first lock action, successive lock actions on the same lock are simply... errr... emphasizing it. And for unlock actions, only the last one (where number of unlock actions = number of lock actions) actually releases the lock. A single wait() call performs all required unlock actions to release the lock on the monitor. And when notify() is called and the thread is reactivated, there will be an equal number of lock actions performed, effectively returning the lock status to exactly what it was before the wait().