This week's book giveaway is in the OO, Patterns, UML and Refactoring forum. We're giving away four copies of Refactoring for Software Design Smells: Managing Technical Debt and have Girish Suryanarayana, Ganesh Samarthyam & Tushar Sharma on-line! See this thread for details.
Could someone confirm (or correct) my understanding of the behavior of wait()? Assume we have three threads, call them A, B, and C, all using a single object, Obj, to synchronize. Assume that threads A and B call Obj.wait() from within code synchronized on Obj. They are now in a wait state on Obj. Thread C then calls Obj.notifyAll() and exits the synchronized block. If A gets the lock and resumes executing, does B go back into wait state? Answer: B does NOT re-enter the wait state, but neither does it own the lock on Obj, even though B's program counter is within a section of synchronized code and is runnable. The thread B blocks till it gets the monitor, and then resumes. Is that right...?
This is a good question - I'm not positive either. The java lang spec says: "The notifyAll method should be called for an object only when the current thread has already locked the object's lock. Every thread in the wait set for the object is removed from the wait set and re-enabled for thread scheduling. (Of course, those threads will not be able to proceed until the current thread relinquishes the object's lock.)" It looks like if the thread can't acquire the lock it's state is pending or blocked until the thread holding the lock releases it but it is not readded to any wait set. I'm surprised they aren't more specific about this - maybe I'm missing something.
Bill, To the best of my understanding, you're correct - B is no longer waiting (having been notified), but it can't run either. B is blocked while it contends for the object's lock. To be picky, I wouldn't actually call B's state "runnable". I like to consider "contending for lock" one of the possible states of a thread. Here's a state diagram I put together when I was studying threads. Jerry
Correct. That is why, when multiple threads may be wait()ing to consume a single message, you use a while loop around the wait(). For example:
The idea is that when a new message is posted, messages.notifyAll() is called. This causes all waiting threads to wake up. One of them will be the first to execute; which one that would be is not defined, but let's call it thread A. Say the message is for this thread and it will be consumed. When it finally releases its lock, thread B will execute. However, for thread B, messages.availableFor() will presumably return false and it will go back to sleep again. Etcetera. - Peter
[This message has been edited by Peter den Haan (edited January 15, 2001).]
Answer: B does NOT re-enter the wait state, but neither does it own the lock on Obj, even though B's program counter is within a section of synchronized code and is runnable. The thread B blocks till it gets the monitor, and then resumes
The Java Tutorial Specifies The notifyAll method wakes up all threads waiting on the object in question. The awakened threads compete for the lock. One thread gets it, and the others go back to waiting. The Object class also defines the notify method, which arbitrarily wakes up one of the threads waiting on this object. Note the line in bold. It looks as if that the threads in the wait queue do not have to have the lock associated with the object to go back into the wait state. The jre puts them back into the wait state. Jerry I do agree that "contending for a lock" is one of the temporary states of a thread . But as soon as one of the threads gets the lock the others will get back into the wait state. Thus i do not agree with your statement
To the best of my understanding, you're correct - B is no longer waiting (having been notified), but it can't run either. B is blocked while it contends for the object's lock. To be picky, I wouldn't actually call B's state "runnable". I like to consider "contending for lock" one of the possible states of a thread
IMHO, The Java Tutorial is at worst wrong, at best unclear, and Bill and the first few posts were essentially correct, with one caveat. notify() and notifyAll() have different behavior regarding what happens to waiting threads. Regarding notify(), the JLS states: "If the wait set for the object is not empty, then some arbitrarily chosen thread is removed from the wait set and re-enabled for thread scheduling." Thus, the other threads that are not chosen are still waiting because they have not been removed from the wait set. Regarding notifyAll(), the JLS states: "Every thread in the wait set for the object is removed from the wait set and re-enabled for thread scheduling" Thus, none of the threads remain in the wait state. One thread gets the lock and executes, the others become blocked. My reference is the 1st ed. of the Java Language Spec. I have the 2nd ed. but it's not where I am right now. I'll check the 2nd ed tomorrow, but I don't expect it to say anything different. Now, back to The Java Tutorial: If by "waiting" they mean going back to a wait state, then according to the JLS, The Java Tutorial is wrong. However, if by "waiting", they mean "blocked", which you could argue means the same thing, then The Java Tutorial is correct in a lose sort of way. Peter Haggar ------------------ author of: Practical Java [This message has been edited by Peter Haggar (edited January 15, 2001).]
Thanks the very helpful input! I think we could resolve the issue above by being somewhat more specific with the word "wait." I believe, from what I've read and seen in experimentation, that thread B (see above) is removed from the wait set for Obj, however it also is "waiting" for the lock on Obj. The difference between these is as follows: wait set: A thread that is in the wait set will not resume execution just because the corresponding lock becomes available; rather, some other thread must call notify() or notifyAll(). (Note that if it is notify() that's called, and more than one thread is in the wait set, then the thread in question must be the one that's picked.) This is the state of Threads A and B before thread C calls notifyAll(). After this, neither threads A nor B is in this state -- they've both been removed from the wait set by notifyAll(). a "waiting" thread: A thread that is not in the wait set may still be blocked "waiting" for a lock on an object. When wait/notify mechanisms are not used, this ordinarily occurs at the very beginning of a synchronized block of code. However, if wait/notify are used, then a thread can be in this "waiting" state somewhere in the middle of the synchronized block. Either way, the only thing that need occur before execution can resume is for the lock to become available and the thread to get the lock. Thread B is in this state. Sound right?
Joined: Jan 03, 2001
Yes, but I think instead of overloading the word "wait", we could just say that a thread that is waiting is, by definition, in the wait set. Otherwise, it is not in the wait set and is either running because it acquired the lock or blocked. Your thread B is blocked on acquiring the object lock. Peter Haggar ------------------ author of: Practical Java
Joined: Jul 28, 2000
For the last few days i have been trying to prove the topic in code. I have been sucessfully been able to do this as given in the code below. Let me summarize what i understand. As most of the people agree a thread does not reenter the wait state once notified. It is in the blocked state and would compete for the object's lock once the lock is available. This is proved by the fact that the first 10 threads are in a wait state in the code below. Once the counter becomes 10 a single notifyAll() is issued. All the threads exit the wait state and sucessfully complete their work by printing out "out of wait". However the remaining 10 threads that is threads names between 10-19 continue to be in the wait state until notified.
Joined: Sep 19, 2000
Rahul, I looked up the tutorial page you referred to in your earlier post. (It's here.) The tutorial is referring to the example they're using to illustrate <code>notifyAll()</code> - in that example, the threads do go back to the wait set. But they don't reenter it on their own - they have to be told to by the next invocation of <code>wait()</code>. Jerry
Joined: Jul 28, 2000
Jerry, You are right in this regard. I guess i should have seen things in the context in which it is being said. Thanks Rahul
I’ve looked at a lot of different solutions, and in my humble opinion Aspose is the way to go. Here’s the link: http://aspose.com