Can notify wake up the same thread multiple times?
java, multithreading, notify, synchronization
Solution
My answer has some implementation specific information. It is based on my working knowledge of Sun JVM and other thread library behavior.
If two producer threads invoke notify, is it guaranteed that two distinct waiting consumer threads will be awoken?
No it is not. There is no guarantee that there will be any consumers awoken. What is guaranteed is that if there are 2 threads that are waiting, then 2 different threads will be put into the run queue.
Or can it be that two `notify()`s fired shortly after each other cause the same comsumer thread to be queued for wakeup twice?
No. Two `notify()` calls will not cause the same consumer thread to be queued twice. It may however, cause one thread to be awoken and there may not be other threads waiting, so the second `notify()` call may do nothing. Of course the thread could have been awoken and then gone right back waiting again and so get the second `notify()` call that way, but I don't think think that is what you are asking.
Does java have some atomic internal operation for waking up threads exactly once?
Yes. The `Thread` code has a number of synchronization points. Once a thread has been notified it is moved out of the `wait` queue. Future calls to `notify()` will look into the `wait` queue and not find the thread.
One more important point. With producer/consumer models, always make sure you are testing the condition in a `while` loop. The reason is that there is race conditions with consumers that are blocked on the lock but not waiting on the condition.
synchronized (workQueue) {
// you must do a while here
while (workQueue.isEmpty()) {
workQueue.wait();
}
workQueue.remove();
}
`Consumer1` could be waiting on `workQueue`. `Consumer2` could be blocked at the `synchronized` but in the run-queue. If something is put into the `workQueue` and `workQueue.notify()` is called. `Consumer2` is put into run-queue now but is behind `Consumer1` who is there first. This is a common implementation. So `Consumer1` goes in a removes the item from the `workQueue` that `Consumer2` was notified about. `Consumer2` has to test again if the `workQueue` is empty otherwise `remove()` will throw because the queue is empty again. See here for more details of the race.
It is also important to realize that spurious wakeups have been documented so the `while` loop protects against a thread being awoken without a `wait()` call.
All this said, if you can reduce your producer/consumer code by using a `BlockingQueue` as recommended in other answers then you should do so. The `BlockingQueue` code already has solved all of these issues.
Problem
Imagine you have a typical producer-consumer pattern in Java. To be a bit more efficient you want to use `notify()` and not `notifyAll()` when a new element is added to the queue. If two producer threads invoke notify, is it guaranteed that two distinct waiting consumer threads will be awoken? Or can it be that two `notify()`s fired shortly after each other cause the same comsumer thread to be queued for wakeup twice? I can't find the section is the API describing how this exactly works. Does java have some atomic internal operation for waking up threads exactly once? If only one comsumer is waiting then the second notify would be lost, that is no problem.