views:

54

answers:

3

some comments here have confused me! I thought I knew this and god knows I've written a ton of MT code, but its been a while and so....

FWIK notify/notifyall

notify: one thread is selected from the waitset and moved to the entryset to acquire monitor lock

notifyall : all threads are "notified" - are they all moved to the entryset ?

Does this mean that they will all reacquire the lock as the lock holder releases it ? no more notify necessary ?

-all answers are just rephrasing what I've read elsewhere. I understand that only one of them can acquire the lock etc., my question this: once a thread is notified, it gets to wait on the monitor. right ? so need not be notified again if the thread holding the lock calls notify

+1  A: 

When notifyAll is called, all threads waiting on that lock are woken up, and one of them acquires the lock. The rest goes back to wait.

This may sound like notifyAll is a waste of resources, but AFAIR there used to be special tricky cases when calling notify may wake up the wrong thread, which can not handle the situation, resulting in a deadlock. Therefore it was recommended to use notifyAll always.

Since Java5 it is rarely necessary to worry about things like this, because the new concurrency utilities almost always handle these tasks better than wait and notify*, rendering them almost obsolete. The typical use of wait and notify* is in blocking queues, and now we have several ready made implementations of these - such as LinkedBlockingQueue and PriorityBlockingQueue - available in the class library.

Péter Török
The threads don't go back to waiting. They all get a turn at acquiring the lock.
Stephen C
@Stephen C, aha, I think now I understand. One lucky thread actually acquires the lock, and the others are free to decide what to do. The typical case is that the call to `wait` is inside a loop, so they will go back to waiting on the lock, however this is not necessary. Is this correct?
Péter Török
@Peter - more precisely, all threads get woken and all get to check the condition. Whether they all see `true` or just one does depends on the condition expression and what the threads do after waking up ...
Stephen C
"Since Java5 it is rarely necessary to worry about things like this, because the new concurrency utilities almost always handle these tasks better than wait and notify*"would you clarify ? AFAIK these wait notify mechanisms are what they use inside anyway. Sure there are higher level synchronization primitives, but at the core its still the same...
unmaskableinterrupt
@unmaskable, yes, the new concurrency utilities use wait/notify internally as needed, to implement a higher level of abstraction. This is why most of the time we don't need to use these primitives directly. Of course, it never hurts to know about them and their proper usage, and one is free to look at the implementation of e.g. LinkedBlockingQueue in order to learn. But in new code I most probably won't ever need to use wait/notify again.
Péter Török
one rule I try to adhere to: whatever layer one works in, it is really helpful to know the innards of the layer that it depends upon. that way you can reason something out rather than try to remember a bunch of disconnected factoids.... thanks for your answer
unmaskableinterrupt
@unmaskableinterrupt - that is a bad rule. A better approach is to thoroughly read and understand the relevant javadocs / specifications, and refresh your memory as required. If you base your understanding on the "innards", you risk writing code that depends on behavior that is outside of the API contract. And that is liable to lead to problems when you try to run your code on some other version of Java. (Of course, the javadoc-driven approach doesn't work in cases where the javadocs are inadequate. But that should be the case here.)
Stephen C
@Stephen, I never said I code based on an understanding of the innards! Of-course, I code to interface etc., What I mean is that knowing the reasoning behind WHY something is designed that way helps one troubleshoot MUCH better and become a better designer. This has helped me tremendously regardless of what language I code in C,C++ or Java. You may never have encountered such issues so I cannot speak for you.
unmaskableinterrupt
+1  A: 

Notification of waiting threads occur when notifyAll is called. All the waiting threads are removed from the object's wait set. Only one of the thread in the wait set is selected, of which there is no guarantee as to which thread is selected

The langspec has a section on Thread Notification

naikus
You misread the specification I think. On `notifyAll`, all of the threads in the lock's waitset are added to the list of threads that are waiting to acquire the lock. Eventually, they will all acquire the lock, though (as you point out) the order in which this occurs is unspecified.
Stephen C
Just to be sure, I am reading it again, but my interpretation is the same. "17.8.2 : If n is greater than zero and this is a notifyAll action, then all threads are removed from m's wait set, and thus resume. Notice however, that only one of them at a time will lock the monitor required during the resumption of wait." Can you please elaborate a bit more?
naikus
spec is not very clear...Lets Say T1, T2, T3 are in the waitset for obja. T4 calls obja.notifyall.T1, T2, T3 and T4 are "notified"/moved ito the "waiting for monitor lock" of obja from obja.waitsetone of them is selected and acquired lock: say T3T3 returns from wait and runs, releases lockT1 T2 and T4 have not yet returned from wait-waiting for lockT1 T2 and T4 content for the lock and one of them acquires and so on. No need to notify them that it has been released because they already were notified. If you agree with me thus far, what happens if T3 calls wait ?
unmaskableinterrupt
spec is not very clear...Lets Say <ul>T1, T2, T3 are in the waitset for obja. </ul>T4 calls obja.notifyall.T1, T2, T3 and T4 are "notified"/moved ito the "waiting for monitor lock" of obja from obja.waitsetone of them is selected and acquired lock: say T3T3 returns from wait and runs, releases lockT1 T2 and T4 have not yet returned from wait-waiting for lockT1 T2 and T4 content for the lock and one of them acquires and so on. No need to notify them that it has been released because they already were notified. If you agree with me thus far, what happens if T3 calls wait ?
unmaskableinterrupt
sorry for the multiple comments I need to read stackoverflow help on formatting!
unmaskableinterrupt
@unmaskableinterrupt, what you are saying is so far correct, so let me explain what happens in that case: T1,T2 and T4 are in runnable state. When T3 calls wait, it releases the lock, at this point any one of T1,T2 or T4 will get to run depending on JVM's underlying thread scheduling policy, thread priority (which thread exactly, is not guaranteed). What happens next depends on how the "run" method of thread was implemented. If these threads were waiting on a condition and that condition was satisfied, then all the threads (at some point) run. But otherwise they will all wait again.
naikus
A follow up to my above comment: while(running) { if(!somecondition) {this.wait()}}
naikus
@naikus, thanks- it helps to think it out. Although from the app perspective notifyAll just means one "notified" thread returns from wait first and then the rest return from wait as the lock becomes available.
unmaskableinterrupt
+1  A: 

For a precise specification of what happens, refer to the JLS section 17.8.2.

When a thread performs a notifyAll on a lock object, all other threads that are currently waiting are removed from the lock's waitset; i.e. they become runable. Each one then tries to reacquire the lock, and when that succeeds it returns from the wait(...) call.

Of course, the threads only succeed in acquiring the lock one at a time, and there are no guarantees of fairness. But eventually, they will all have acquired the lock.

Stephen C