Java: notify() vs. notifyAll() all over again
Asked Answered
C

26

424

If one Googles for "difference between notify() and notifyAll()" then a lot of explanations will pop up (leaving apart the javadoc paragraphs). It all boils down to the number of waiting threads being waken up: one in notify() and all in notifyAll().

However (if I do understand the difference between these methods right), only one thread is always selected for further monitor acquisition; in the first case the one selected by the VM, in the second case the one selected by the system thread scheduler. The exact selection procedures for both of them (in the general case) are not known to the programmer.

What's the useful difference between notify() and notifyAll() then? Am I missing something?

Coagulase answered 31/8, 2008 at 18:47 Comment(5)
The useful libraries to use for concurrency are in the concurrency libraries. I suggest these are a better choice in almost every case. The Concurency library pre date Java 5.0 (in which is were they were added as standard in 2004)Suint
I disagree with Peter. The concurrency library is implemented in Java, and there is a lot of Java code executed every time you call lock(), unlock(), etc. You can shoot yourself in the foot by using concurrency library instead of good old synchronized, except for certain, rather rare use cases.Harrietharriett
The key misunderstanding seems to be this: ... only one thread is always selected for further monitor acquisition; in the first case the one selected by the VM, in the second case the one selected by the system thread scheduler. The implication being that the are essentially the same. While the behavior as described is correct, what's missing is that in the notifyAll() case, _the other threads after the first remain awake and will acquire the monitor, one-by-one. In the notify case, none of the other threads are even woken. So functionally they are very different!Rosy
1) If many threads are waiting on an object, and notify() is called only once on that object. Except one of the waiting threads the remaining threads wait forever ? 2) If notify() is used only one of many waiting thread starts executing. If notifyall() is used all waiting threads are notified but only one of them starts executing, so what is the use of notifyall() here ?Signorina
@ChetanGowda Notifying all threads vs Notify exactly only one arbitrary thread actually has significant difference until that seemingly subtle but important difference strikes us.When you notify() only 1 thread,all the other threads will be in waiting state until it receives an explicit notification/signal. Notifying all, all the threads will be executed and completed in some order one after the other without any further notification - here we should say the threads are blocked and not waiting.When blocked its exec is suspended temporarily until another thread is inside the sync block.Sulfapyridine
S
269

However (if I do understand the difference between these methods right), only one thread is always selected for further monitor acquisition.

That is not correct. o.notifyAll() wakes all of the threads that are blocked in o.wait() calls. The threads are only allowed to return from o.wait() one-by-one, but they each will get their turn.


Simply put, it depends on why your threads are waiting to be notified. Do you want to tell one of the waiting threads that something happened, or do you want to tell all of them at the same time?

In some cases, all waiting threads can take useful action once the wait finishes. An example would be a set of threads waiting for a certain task to finish; once the task has finished, all waiting threads can continue with their business. In such a case you would use notifyAll() to wake up all waiting threads at the same time.

Another case, for example mutually exclusive locking, only one of the waiting threads can do something useful after being notified (in this case acquire the lock). In such a case, you would rather use notify(). Properly implemented, you could use notifyAll() in this situation as well, but you would unnecessarily wake threads that can't do anything anyway.


In many cases, the code to await a condition will be written as a loop:

synchronized(o) {
    while (! IsConditionTrue()) {
        o.wait();
    }
    DoSomethingThatOnlyMakesSenseWhenConditionIsTrue_and_MaybeMakeConditionFalseAgain();
}

That way, if an o.notifyAll() call wakes more than one waiting thread, and the first one to return from the o.wait() makes leaves the condition in the false state, then the other threads that were awakened will go back to waiting.

Sackville answered 31/8, 2008 at 19:25 Comment(11)
if you notify just one thread but multiple are waiting on an object, how does the VM determine which one to notify?Plumbing
I can't say for certain about the Java spec, but generally you should avoid making assumptions about such details. I think you can assume that the VM will do it in a sane and mostly fair way, though.Sackville
Do you want to tell one of the waiting threads that something happened, or do you want to tell all of them at the same time? Good ExplanationBridgework
Liedman is severely wrong, the Java specification explicitly states that the notify() is not guaranteed to be fair. i.e. each call to notify might wake the same thread again (the thread queue in the monitor is NOT FAIR or FIFO). However the scheduler is guaranteed to be fair. Which is why in most cases where you have more than 2 threads you should prefer notifyAll.Feeble
@YannTM I'm all for constructive critisism, but I think your tone is a bit unfair. I explicitly said "can't say for certain" and "I think". Ease up, did you ever write something seven years ago that wasn't 100% correct?Sackville
The problem is that this is the accepted answer, it's not a question of personal pride. If you know you were wrong now, please edit your answer to say it, and point to e.g. xagyg pedagogic and correct answer below.Feeble
@Sackville Your answer sounds good, but based on that another question arrises. If I do notifyall() and it wakes up all the thread that was in waiting queue you agree that only one thread can access the lock and enter in the that synchronized block or method and based on that naturally other thread wont get chances to enter the locked section, so they end up being in waiting state. Dont you think eventually its same thing?I am just trying to clarify it. As of now every where it says notify wakes one and notifyAll wakes up all but in both cases only one thread can get locks. So whats the diff?Virescent
Thanks for the explanation, (in this case acquire the lock) is the main difference I guess.Sextain
@MrA The difference is, in notifyAll() other threads do not go to waiting state, it goes to blocked state. waiting - you "wait" for a notification from another thread and it is a communication between the threads, blocked - once a thread finishes the critical section/synchronized block, an OS scheduler decides to run the next thread and all the threads see their completion in some order in a synchronized manner (unless you make the other threads go to waiting state again).Sulfapyridine
@MrA In notify() threads may end up waiting endlessly for a notification because some thread is notified which cannot make any progress instead of a thread which can make progress and if there is a possibility that it can happen in your system/implementation and if you find that your application may not work or proceed as intended if that happens, then notifyAll() is the correct construct.Sulfapyridine
@YannTM where in the specification did you find the statement “the scheduler is guaranteed to be fair”? There’s no such fairness guaranty, and therefore, using notifyAll just for that purpose is pointless.Memorandum
O
380

Clearly, notify wakes (any) one thread in the wait set, notifyAll wakes all threads in the waiting set. The following discussion should clear up any doubts. notifyAll should be used most of the time. If you are not sure which to use, then use notifyAll.Please see explanation that follows.

Read very carefully and understand. Please send me an email if you have any questions.

Look at producer/consumer (assumption is a ProducerConsumer class with two methods). IT IS BROKEN (because it uses notify) - yes it MAY work - even most of the time, but it may also cause deadlock - we will see why:

public synchronized void put(Object o) {
    while (buf.size()==MAX_SIZE) {
        wait(); // called if the buffer is full (try/catch removed for brevity)
    }
    buf.add(o);
    notify(); // called in case there are any getters or putters waiting
}

public synchronized Object get() {
    // Y: this is where C2 tries to acquire the lock (i.e. at the beginning of the method)
    while (buf.size()==0) {
        wait(); // called if the buffer is empty (try/catch removed for brevity)
        // X: this is where C1 tries to re-acquire the lock (see below)
    }
    Object o = buf.remove(0);
    notify(); // called if there are any getters or putters waiting
    return o;
}

FIRSTLY,

Why do we need a while loop surrounding the wait?

We need a while loop in case we get this situation:

Consumer 1 (C1) enter the synchronized block and the buffer is empty, so C1 is put in the wait set (via the wait call). Consumer 2 (C2) is about to enter the synchronized method (at point Y above), but Producer P1 puts an object in the buffer, and subsequently calls notify. The only waiting thread is C1, so it is woken and now attempts to re-acquire the object lock at point X (above).

Now C1 and C2 are attempting to acquire the synchronization lock. One of them (nondeterministically) is chosen and enters the method, the other is blocked (not waiting - but blocked, trying to acquire the lock on the method). Let's say C2 gets the lock first. C1 is still blocking (trying to acquire the lock at X). C2 completes the method and releases the lock. Now, C1 acquires the lock. Guess what, lucky we have a while loop, because, C1 performs the loop check (guard) and is prevented from removing a non-existent element from the buffer (C2 already got it!). If we didn't have a while, we would get an IndexArrayOutOfBoundsException as C1 tries to remove the first element from the buffer!

NOW,

Ok, now why do we need notifyAll?

In the producer/consumer example above it looks like we can get away with notify. It seems this way, because we can prove that the guards on the wait loops for producer and consumer are mutually exclusive. That is, it looks like we cannot have a thread waiting in the put method as well as the get method, because, for that to be true, then the following would have to be true:

buf.size() == 0 AND buf.size() == MAX_SIZE (assume MAX_SIZE is not 0)

HOWEVER, this is not good enough, we NEED to use notifyAll. Let's see why ...

Assume we have a buffer of size 1 (to make the example easy to follow). The following steps lead us to deadlock. Note that ANYTIME a thread is woken with notify, it can be non-deterministically selected by the JVM - that is any waiting thread can be woken. Also note that when multiple threads are blocking on entry to a method (i.e. trying to acquire a lock), the order of acquisition can be non-deterministic. Remember also that a thread can only be in one of the methods at any one time - the synchronized methods allow only one thread to be executing (i.e. holding the lock of) any (synchronized) methods in the class. If the following sequence of events occurs - deadlock results:

STEP 1:
- P1 puts 1 char into the buffer

STEP 2:
- P2 attempts put - checks wait loop - already a char - waits

STEP 3:
- P3 attempts put - checks wait loop - already a char - waits

STEP 4:
- C1 attempts to get 1 char
- C2 attempts to get 1 char - blocks on entry to the get method
- C3 attempts to get 1 char - blocks on entry to the get method

STEP 5:
- C1 is executing the get method - gets the char, calls notify, exits method
- The notify wakes up P2
- BUT, C2 enters method before P2 can (P2 must reacquire the lock), so P2 blocks on entry to the put method
- C2 checks wait loop, no more chars in buffer, so waits
- C3 enters method after C2, but before P2, checks wait loop, no more chars in buffer, so waits

STEP 6:
- NOW: there is P3, C2, and C3 waiting!
- Finally P2 acquires the lock, puts a char in the buffer, calls notify, exits method

STEP 7:
- P2's notification wakes P3 (remember any thread can be woken)
- P3 checks the wait loop condition, there is already a char in the buffer, so waits.
- NO MORE THREADS TO CALL NOTIFY and THREE THREADS PERMANENTLY SUSPENDED!

SOLUTION: Replace notify with notifyAll in the producer/consumer code (above).

Occupier answered 6/7, 2010 at 12:58 Comment(32)
There is an alternative: if the woken thread (P3 in your example) does not detect the condition it is interested in then it calls notify() again. That way notify() is called as many times as necessary until one thread is able to proceed.Milkandwater
finnw - P3 must re-check the condition because the notify causes P3 (the selected thread in this example) to proceed from the point it was waiting (i.e. within the while loop). There are other examples that do not cause deadlock, however, in this case the use of notify does not guarantee deadlock-free code. The use of notifyAll does.Occupier
@xagyg, the condition must be repeatedly checked until there is a char in the buffer, but it can either be the same thread (in a wait/check loop) or a cycle of threads notifying each other until one finds a char in the buffer.Milkandwater
Let me see if I understand it: there are 2 places where a thread may get stuck: waiting in wait(), or trying to acquire the lock after it wakes up from wait(). After a notifyAll(), all threads wake up, but only 1 will be able to reacquire the lock. After a notify(), only 1 thread wakes up, and others continue to wait for another notify().Dolor
Hi @Occupier , Would calling notifyAll() lead to multiple waiting thread checking the while() condition at the same time .. and hence there is a possibility that before the while gets saitsfied, 2 threads are already out of it causing outOfBound exception ?. Also I modified my small code based on your solution, I will appreciate if you can please review it :codereview.stackexchange.com/questions/3157/…Hatchway
@xagyg, The example sequence is incomplete. "NO MORE THREADS TO CALL NOTIFY" is not true, given only p3, c2 and c3 are waiting - p1, p2 and c1 can still call put and get, and notify the others. To complete the deadlocking sequence: p1 and p2 should try to put, and wait because the buffer is full. c1 should then get a char, and notify c2. Next, c1 and c2 should try to get another char, and wait because the buffer is empty. Only then will you have 3 producers and 3 consumers waiting, with no-one to call notify.Spiculate
@Dolor Very close. With notifyAll, each thread will reacquire the lock (one at a time), but note that after one thread has reacquired the lock and executed the method (and then exited) ... the next thread reacquires the lock, checks the "while" and will go back to "wait" (depending on what the condition is of course). So, notify wakes one thread - as you correctly state. notifyAll wakes all threads and each thread reacquires the lock one at a time - checks the condition of the "while" and either executes the method or "waits" again.Occupier
@eran your description is incorrect. For one, p1 has already completed. I won't go on.Occupier
@Milkandwater I think not. Good luck with your programming. Thanks for the time you spent to look at it though. If anyone wants further information on this, I can send some very detailed formal specification of how Java multithreading works. There seems to be much misconception about it.Occupier
@xagyg, are you talking about a scenario in which every producer has only one single char to store? If so, your example is correct, but not very interesting IMO. With the additional steps I suggest, you can deadlock the same system, but with an unbounded amount of input - which is how such patterns are usually being used in reality.Spiculate
The usage of notify vs notifyall in 2nd example does not cause deadlock. Is thread starvationPhilps
@Ovidiu it depends on your definition. The type of deadlock described in the example could be more specifically termed "dormancy" (after Doug Lea). Another common type of deadlock is "deadly embrace" (a different problem to the one in the example). People generally use the term deadlock for liveness failures. I reserve the term "starvation" for situations involving contention (and specifically the way the JVM can cause starvation through its non-deterministic provision of locks to threads entering critical sections).Occupier
@Hatchway You asked: "Would calling notifyAll() lead to multiple waiting thread checking the while() condition at the same time .. and hence there is a possibility that before the while gets saitsfied, 2 threads are already out of it causing outOfBound exception ?." No, this is not possible, since although multiple threads would wake up, they cannot check the while condition at the same time. They are each required to re-attain the lock (immediately after the wait) before they can re-enter the code section and re-check the while. Therefore, one at a time.Occupier
@Occupier nice example. This is off topic from the original question; just for sake of discussion. The deadlock is a design problem imo (correct me if I am wrong). Because you have one lock shared by both put and get. And JVM is not smart enough to call put after a get release the lock and vice verse. The dead lock happens because put wakes up another put, which put itself back to wait() because of while(). Would making two classes (and two locks) work? So put{synchonized(get)}, get{(synchonized(put)}. In other words, get will wake put only, and put will wake get only.Mf
@Mf what if there are no consumers waiting? producers still need to guard against each other, so if there is a lot of contention only from producers then they will need to notify each other on the producer lock. under other circumstances there could be consumers waiting, so you would need to notify them too in general ..... it seems like 3 locks are needed, a producer first acquires the producer lock then exactly 1 producer waits for the joint producer-consumer lock, similarly, a consumer first acquires the consumer lock and then exactly 1 consumer waits for the joint lock. works?Ferdelance
@Occupier Thanks for explanation, the problem is clearly explained. I still think that you could safely use notify in your example if you use two separate locks: one for blocking on empty queue, another for blocking on full queue. Am I missing something ?Lipography
Is there any way we can get rid of the while loop and maybe double check the condition? I don't think it's possible and that's what I answered in the interview but I wanted to confirm.Enwomb
@Enwomb You are correct. There is no way to remove the while loop.Occupier
@Lipography The approach you are proposing is common for concurrency systems designed to wait or signal on a condition. Java does not provide the necessary mechanisms to support this approach. Using two locks to solve this problem won't work with Java.Occupier
@Mf intuitively it seems that two locks may work ... because we were taught this way at university. However, that wasn't using Java, that was using concurrent systems that support waiting/signalling on a condition. Java doesn't support this. You cannot wait on a condition in Java and then signal threads waiting on that condition. As we know Java signal wakes all threads. So, no, two locks will not work and you'll run into race conditions with gets and puts trying to get/put to the same queue/buffer.Occupier
@Occupier I'm confused about your C1 and C2 entering point on X and Y. How two thread can be entered to synchronized block/method?Exteriorize
@Occupier Is not the case that notifyAll() can also lead to deadlock. Ultimately, after notifyAll() only one thread is going to run. What if even after using notifyAll() all the conditions that you have shown is met then in that case also deadlock happens.Solita
@UnKnown When C1 calls wait(), it will release the lock, thus C2 can enter the synchronized block.Columbian
@Solita notifyAll() will wake all threads, but only 1 thread can get the lock and run. If that thread is leaving the synchronized block or go to wait() again, other threads may have chance to gain the lock and begin to run.Columbian
@Occupier You write that we cannot have a thread waiting in the put method as well as a thread waiting in the get method. But this is not true, right?. Look at your own example, where producer as well as consumer are waiting.Dudley
@Dudley No. I said it "looks like" that. I explain in the example how it is possible.Occupier
So the issue is that a Producer calling wake may wake up another Producer, which is a pointless wake-up. (or vice versa, a Consumer might wake up another Consumer). This could be also fixed by using two separate condition variables.Rattish
@Rattish yes, if notify is called, in certain cases, it is not only pointless, but potentially blocking (as described in the example).Occupier
@Milkandwater calling notify would prevent deadlock in this case, but imagine there's P4 also waiting alongside P3, it's possible you wake P4 instead of consumer and it's possible P3 and P4 would be waking each other indefinitely, so it doen't solve deadlock. Besides if there are no consumers two waiting producers will keep waking each other wasting cpu time.Few
@eran "are you talking about a scenario in which every producer has only one single char to store?" - it could be a scenario where producers are temporary by nature, e.g. thread serving HTTP request, your app can do some HTTP exchange, then stay dormant for say 1 hour, all this time having stalled unserved request in queue. Even if it breaks deadlock eventually, it's still a nasty bug.Few
Great explanation, yet I wonder what's required for deadlocking queue of realistic size, 20 for example. Say queue is full, we have 21 producers waiting, then 20 consumers come, take 20 elements, notify 20 producers, then 21st consumer comes, sees empty queue and starts waiting, then 20 notified producers put their element each time notifying 21st producer or each other, queue is full again and we have 21 producers and one consumer sleeping. Is this an impossible coincedence?Few
@Few Ultimately we need a situation (at a minimum) where there is at least one producer and one consumer thread waiting. The example uses a capacity of 1 for simplicity (but any size can be used). In your example scenario, if 21 producers put to a buffer of 20, then 1 producer will be waiting, which satisfies part of the condition for deadlock to occur. In my example, two producers "put", therefore one producer waiting, would partially satisfy the condition. The number of puts/gets to get to that condition is really the only difference.Occupier
S
269

However (if I do understand the difference between these methods right), only one thread is always selected for further monitor acquisition.

That is not correct. o.notifyAll() wakes all of the threads that are blocked in o.wait() calls. The threads are only allowed to return from o.wait() one-by-one, but they each will get their turn.


Simply put, it depends on why your threads are waiting to be notified. Do you want to tell one of the waiting threads that something happened, or do you want to tell all of them at the same time?

In some cases, all waiting threads can take useful action once the wait finishes. An example would be a set of threads waiting for a certain task to finish; once the task has finished, all waiting threads can continue with their business. In such a case you would use notifyAll() to wake up all waiting threads at the same time.

Another case, for example mutually exclusive locking, only one of the waiting threads can do something useful after being notified (in this case acquire the lock). In such a case, you would rather use notify(). Properly implemented, you could use notifyAll() in this situation as well, but you would unnecessarily wake threads that can't do anything anyway.


In many cases, the code to await a condition will be written as a loop:

synchronized(o) {
    while (! IsConditionTrue()) {
        o.wait();
    }
    DoSomethingThatOnlyMakesSenseWhenConditionIsTrue_and_MaybeMakeConditionFalseAgain();
}

That way, if an o.notifyAll() call wakes more than one waiting thread, and the first one to return from the o.wait() makes leaves the condition in the false state, then the other threads that were awakened will go back to waiting.

Sackville answered 31/8, 2008 at 19:25 Comment(11)
if you notify just one thread but multiple are waiting on an object, how does the VM determine which one to notify?Plumbing
I can't say for certain about the Java spec, but generally you should avoid making assumptions about such details. I think you can assume that the VM will do it in a sane and mostly fair way, though.Sackville
Do you want to tell one of the waiting threads that something happened, or do you want to tell all of them at the same time? Good ExplanationBridgework
Liedman is severely wrong, the Java specification explicitly states that the notify() is not guaranteed to be fair. i.e. each call to notify might wake the same thread again (the thread queue in the monitor is NOT FAIR or FIFO). However the scheduler is guaranteed to be fair. Which is why in most cases where you have more than 2 threads you should prefer notifyAll.Feeble
@YannTM I'm all for constructive critisism, but I think your tone is a bit unfair. I explicitly said "can't say for certain" and "I think". Ease up, did you ever write something seven years ago that wasn't 100% correct?Sackville
The problem is that this is the accepted answer, it's not a question of personal pride. If you know you were wrong now, please edit your answer to say it, and point to e.g. xagyg pedagogic and correct answer below.Feeble
@Sackville Your answer sounds good, but based on that another question arrises. If I do notifyall() and it wakes up all the thread that was in waiting queue you agree that only one thread can access the lock and enter in the that synchronized block or method and based on that naturally other thread wont get chances to enter the locked section, so they end up being in waiting state. Dont you think eventually its same thing?I am just trying to clarify it. As of now every where it says notify wakes one and notifyAll wakes up all but in both cases only one thread can get locks. So whats the diff?Virescent
Thanks for the explanation, (in this case acquire the lock) is the main difference I guess.Sextain
@MrA The difference is, in notifyAll() other threads do not go to waiting state, it goes to blocked state. waiting - you "wait" for a notification from another thread and it is a communication between the threads, blocked - once a thread finishes the critical section/synchronized block, an OS scheduler decides to run the next thread and all the threads see their completion in some order in a synchronized manner (unless you make the other threads go to waiting state again).Sulfapyridine
@MrA In notify() threads may end up waiting endlessly for a notification because some thread is notified which cannot make any progress instead of a thread which can make progress and if there is a possibility that it can happen in your system/implementation and if you find that your application may not work or proceed as intended if that happens, then notifyAll() is the correct construct.Sulfapyridine
@YannTM where in the specification did you find the statement “the scheduler is guaranteed to be fair”? There’s no such fairness guaranty, and therefore, using notifyAll just for that purpose is pointless.Memorandum
U
50

Useful differences:

  • Use notify() if all your waiting threads are interchangeable (the order they wake up doesn't matter), or if you only ever have one waiting thread. A common example is a thread pool used to execute jobs from a queue--when a job is added, one of threads is notified to wake up, execute the next job and go back to sleep.

  • Use notifyAll() for other cases where the waiting threads may have different purposes and should be able to run concurrently. An example is a maintenance operation on a shared resource, where multiple threads are waiting for the operation to complete before accessing the resource.

Untruth answered 31/8, 2008 at 19:41 Comment(0)
S
19

I think it depends on how resources are produced and consumed. If 5 work objects are available at once and you have 5 consumer objects, it would make sense to wake up all threads using notifyAll() so each one can process 1 work object.

If you have just one work object available, what is the point in waking up all consumer objects to race for that one object? The first one checking for available work will get it and all other threads will check and find they have nothing to do.

I found a great explanation here. In short:

The notify() method is generally used for resource pools, where there are an arbitrary number of "consumers" or "workers" that take resources, but when a resource is added to the pool, only one of the waiting consumers or workers can deal with it. The notifyAll() method is actually used in most other cases. Strictly, it is required to notify waiters of a condition that could allow multiple waiters to proceed. But this is often difficult to know. So as a general rule, if you have no particular logic for using notify(), then you should probably use notifyAll(), because it is often difficult to know exactly what threads will be waiting on a particular object and why.

Strathspey answered 31/8, 2008 at 19:25 Comment(0)
I
12

Note that with concurrency utilities you also have the choice between signal() and signalAll() as these methods are called there. So the question remains valid even with java.util.concurrent.

Doug Lea brings up an interesting point in his famous book: if a notify() and Thread.interrupt() happen at the same time, the notify might actually get lost. If this can happen and has dramatic implications notifyAll() is a safer choice even though you pay the price of overhead (waking too many threads most of the time).

Issus answered 17/6, 2009 at 11:41 Comment(0)
L
10

Here is an example. Run it. Then change one of the notifyAll() to notify() and see what happens.

ProducerConsumerExample class

public class ProducerConsumerExample {

    private static boolean Even = true;
    private static boolean Odd = false;

    public static void main(String[] args) {
        Dropbox dropbox = new Dropbox();
        (new Thread(new Consumer(Even, dropbox))).start();
        (new Thread(new Consumer(Odd, dropbox))).start();
        (new Thread(new Producer(dropbox))).start();
    }
}

Dropbox class

public class Dropbox {

    private int number;
    private boolean empty = true;
    private boolean evenNumber = false;

    public synchronized int take(final boolean even) {
        while (empty || evenNumber != even) {
            try {
                System.out.format("%s is waiting ... %n", even ? "Even" : "Odd");
                wait();
            } catch (InterruptedException e) { }
        }
        System.out.format("%s took %d.%n", even ? "Even" : "Odd", number);
        empty = true;
        notifyAll();

        return number;
    }

    public synchronized void put(int number) {
        while (!empty) {
            try {
                System.out.println("Producer is waiting ...");
                wait();
            } catch (InterruptedException e) { }
        }
        this.number = number;
        evenNumber = number % 2 == 0;
        System.out.format("Producer put %d.%n", number);
        empty = false;
        notifyAll();
    }
}

Consumer class

import java.util.Random;

public class Consumer implements Runnable {

    private final Dropbox dropbox;
    private final boolean even;

    public Consumer(boolean even, Dropbox dropbox) {
        this.even = even;
        this.dropbox = dropbox;
    }

    public void run() {
        Random random = new Random();
        while (true) {
            dropbox.take(even);
            try {
                Thread.sleep(random.nextInt(100));
            } catch (InterruptedException e) { }
        }
    }
}

Producer class

import java.util.Random;

public class Producer implements Runnable {

    private Dropbox dropbox;

    public Producer(Dropbox dropbox) {
        this.dropbox = dropbox;
    }

    public void run() {
        Random random = new Random();
        while (true) {
            int number = random.nextInt(10);
            try {
                Thread.sleep(random.nextInt(100));
                dropbox.put(number);
            } catch (InterruptedException e) { }
        }
    }
}
Lattice answered 21/5, 2010 at 3:34 Comment(0)
W
10

Short summary:

Always prefer notifyAll() over notify() unless you have a massively parallel application where a large number of threads all do the same thing.

Explanation:

notify() [...] wakes up a single thread. Because notify() doesn't allow you to specify the thread that is woken up, it is useful only in massively parallel applications — that is, programs with a large number of threads, all doing similar chores. In such an application, you don't care which thread gets woken up.

source: https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html

Compare notify() with notifyAll() in the above described situation: a massively parallel application where threads are doing the same thing. If you call notifyAll() in that case, notifyAll() will induce the waking up (i.e. scheduling) of a huge number of threads, many of them unnecessarily (since only one thread can actually proceed, namely the thread which will be granted the monitor for the object wait(), notify(), or notifyAll() was called on), therefore wasting computing resources.

Thus, if you don't have an application where a huge number of threads do the same thing concurrently, prefer notifyAll() over notify(). Why? Because, as other users have already answered in this forum, notify()

wakes up a single thread that is waiting on this object's monitor. [...] The choice is arbitrary and occurs at the discretion of the implementation.

source: Java SE8 API (https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#notify--)

Imagine you have a producer consumer application where consumers are ready (i.e. wait() ing) to consume, producers are ready (i.e. wait() ing) to produce and the queue of items (to be produced / consumed) is empty. In that case, notify() might wake up only consumers and never producers because the choice who is waken up is arbitrary. The producer consumer cycle wouldn't make any progress although producers and consumers are ready to produce and consume, respectively. Instead, a consumer is woken up (i.e. leaving the wait() status), doesn't take an item out of the queue because it's empty, and notify() s another consumer to proceed.

In contrast, notifyAll() awakens both producers and consumers. The choice who is scheduled depends on the scheduler. Of course, depending on the scheduler's implementation, the scheduler might also only schedule consumers (e.g. if you assign consumer threads a very high priority). However, the assumption here is that the danger of the scheduler scheduling only consumers is lower than the danger of the JVM only waking up consumers because any reasonably implemented scheduler doesn't make just arbitrary decisions. Rather, most scheduler implementations make at least some effort to prevent starvation.

Wakefield answered 25/10, 2015 at 11:10 Comment(0)
M
9

There are three states for a thread.

  1. WAIT - The thread is not using any CPU cycle
  2. BLOCKED - The thread is blocked trying to acquire a monitor. It might still be using the CPU cycles
  3. RUNNING - The thread is running.

Now, when a notify() is called, JVM picks one thread and move them to the BLOCKED state and hence to the RUNNING state as there is no competition for the monitor object.

When a notifyAll() is called, JVM picks all the threads and move all of them to BLOCKED state. All these threads will get the lock of the object on a priority basis. Thread which is able to acquire the monitor first will be able to go to the RUNNING state first and so on.

Morbific answered 8/1, 2017 at 7:46 Comment(1)
Just awesome explanation.Shed
S
8

From Joshua Bloch, the Java Guru himself in Effective Java 2nd edition:

"Item 69: Prefer concurrency utilities to wait and notify".

Salim answered 3/9, 2008 at 14:26 Comment(2)
The why is more important than the source.Jurist
@Jurist Well said. I would be more interested in finding out the reasons as well. One possible reason could be that wait and notify in the object class are based on an implicit condition variable. So in the standard producer and consumer example.....both producer and consumer will wait on the same condition which could lead to a deadlock as explained by xagyg in his answer. So a better approach is to use 2 condition variables as explained in docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/…Temekatemerity
P
7

This answer is a graphical rewriting and simplification of the excellent answer by xagyg, including comments by eran.

Why use notifyAll, even when each product is intended for a single consumer?

Consider producers and consumers, simplified as follows.

Producer:

while (!empty) {
   wait() // on full
}
put()
notify()

Consumer:

while (empty) {
   wait() // on empty
}
take()
notify()

Assume 2 producers and 2 consumers, sharing a buffer of size 1. The following picture depicts a scenario leading to a deadlock, which would be avoided if all threads used notifyAll.

Each notify is labeled with the thread being woken up.

deadlock due to notify

Phosphorus answered 25/5, 2017 at 8:17 Comment(0)
B
5

I am very surprised that no one mentioned the infamous "lost wakeup" problem (google it).

Basically:

  1. if you have multiple threads waiting on a same condition and,
  2. multiple threads that can make you transition from state A to state B and,
  3. multiple threads that can make you transition from state B to state A (usually the same threads as in 1.) and,
  4. transitioning from state A to B should notify threads in 1.

THEN you should use notifyAll unless you have provable guarantees that lost wakeups are impossible.

A common example is a concurrent FIFO queue where: multiple enqueuers (1. and 3. above) can transition your queue from empty to non-empty multiple dequeuers (2. above) can wait for the condition "the queue is not empty" empty -> non-empty should notify dequeuers

You can easily write an interleaving of operations in which, starting from an empty queue, 2 enqueuers and 2 dequeuers interact and 1 enqueuer will remain sleeping.

This is a problem arguably comparable with the deadlock problem.

Bioscopy answered 15/9, 2012 at 16:50 Comment(2)
My apologies, xagyg explains it in detail. The name for the problem is "lost wakeup"Bioscopy
@Abhay Bansal: I think you are missing the fact that condition.wait() releases the lock and it gets reacquired by the thread that wakes up.Bioscopy
S
5

Here's a simpler explanation:

You're correct that whether you use notify() or notifyAll(), the immediate result is that exactly one other thread will acquire the monitor and begin executing. (Assuming some threads were in fact blocked on wait() for this object, other unrelated threads aren't soaking up all available cores, etc.) The impact comes later.

Suppose thread A, B, and C were waiting on this object, and thread A gets the monitor. The difference lies in what happens once A releases the monitor. If you used notify(), then B and C are still blocked in wait(): they are not waiting on the monitor, they are waiting to be notified. When A releases the monitor, B and C will still be sitting there, waiting for a notify().

If you used notifyAll(), then B and C have both advanced past the "wait for notification" state and are both waiting to acquire the monitor. When A releases the monitor, either B or C will acquire it (assuming no other threads are competing for that monitor) and begin executing.

Singleaction answered 25/6, 2013 at 0:18 Comment(1)
Very clear explanation. The result of this behavior of notify() can lead to "Missed Signal"/"Missed Notification" leading to deadlock/no progress situation of the application state.P-Producer,C-Consumer P1, P2 and C2 are waiting for C1. C1 calls notify() and is meant for a producer but C2 can be woken up and so both P1 and P2 missed the notification and ll be waiting for further explicit "notification" (a notify() call).Sulfapyridine
A
4

notify() will wake up one thread while notifyAll() will wake up all. As far as I know there is no middle ground. But if you are not sure what notify() will do to your threads, use notifyAll(). Works like a charm everytime.

Abamp answered 31/8, 2008 at 19:19 Comment(0)
K
4

All the above answers are correct, as far as I can tell, so I'm going to tell you something else. For production code you really should use the classes in java.util.concurrent. There is very little they cannot do for you, in the area of concurrency in java.

Kendall answered 31/8, 2008 at 19:50 Comment(0)
H
4

notify() lets you write more efficient code than notifyAll().

Consider the following piece of code that's executed from multiple parallel threads:

synchronized(this) {
    while(busy) // a loop is necessary here
        wait();
    busy = true;
}
...
synchronized(this) {
    busy = false;
    notifyAll();
}

It can be made more efficient by using notify():

synchronized(this) {
    if(busy)   // replaced the loop with a condition which is evaluated only once
        wait();
    busy = true;
}
...
synchronized(this) {
    busy = false;
    notify();
}

In the case if you have a large number of threads, or if the wait loop condition is costly to evaluate, notify() will be significantly faster than notifyAll(). For example, if you have 1000 threads then 999 threads will be awakened and evaluated after the first notifyAll(), then 998, then 997, and so on. On the contrary, with the notify() solution, only one thread will be awakened.

Use notifyAll() when you need to choose which thread will do the work next:

synchronized(this) {
    while(idx != last+1)  // wait until it's my turn
        wait();
}
...
synchronized(this) {
    last = idx;
    notifyAll();
}

Finally, it's important to understand that in case of notifyAll(), the code inside synchronized blocks that have been awakened will be executed sequentially, not all at once. Let's say there are three threads waiting in the above example, and the fourth thread calls notifyAll(). All three threads will be awakened but only one will start execution and check the condition of the while loop. If the condition is true, it will call wait() again, and only then the second thread will start executing and will check its while loop condition, and so on.

Harrietharriett answered 17/6, 2013 at 23:23 Comment(0)
B
4

notify() - Selects a random thread from the wait set of the object and puts it in the BLOCKED state. The rest of the threads in the wait set of the object are still in the WAITING state.

notifyAll() - Moves all the threads from the wait set of the object to BLOCKED state. After you use notifyAll(), there are no threads remaining in the wait set of the shared object because all of them are now in BLOCKED state and not in WAITING state.

BLOCKED - blocked for lock acquisition. WAITING - waiting for notify ( or blocked for join completion ).

Birnbaum answered 25/10, 2015 at 12:56 Comment(0)
S
3

I would like to mention what is explained in Java Concurrency in Practice:

First point, whether Notify or NotifyAll?

It will be NotifyAll, and reason is that it will save from signall hijacking.

If two threads A and B are waiting on different condition predicates of same condition queue and notify is called, then it is upto JVM to which thread JVM will notify.

Now if notify was meant for thread A and JVM notified thread B, then thread B will wake up and see that this notification is not useful so it will wait again. And Thread A will never come to know about this missed signal and someone hijacked it's notification.

So, calling notifyAll will resolve this issue, but again it will have performance impact as it will notify all threads and all threads will compete for same lock and it will involve context switch and hence load on CPU. But we should care about performance only if it is behaving correctly, if it's behavior itself is not correct then performance is of no use.

This problem can be solved with using Condition object of explicit locking Lock, provided in jdk 5, as it provides different wait for each condition predicate. Here it will behave correctly and there will not be performance issue as it will call signal and make sure that only one thread is waiting for that condition

Splash answered 6/9, 2013 at 5:34 Comment(0)
B
3

Taken from blog on Effective Java:

The notifyAll method should generally be used in preference to notify. 

If notify is used, great care must be taken to ensure liveness.

So, what i understand is (from aforementioned blog, comment by "Yann TM" on accepted answer and Java docs):

  • notify() : JVM awakens one of the waiting threads on this object. Thread selection is made arbitrarily without fairness. So same thread can be awakened again and again. So system's state changes but no real progress is made. Thus creating a livelock.
  • notifyAll() : JVM awakens all threads and then all threads race for the lock on this object. Now, CPU scheduler selects a thread which acquires lock on this object. This selection process would be much better than selection by JVM. Thus, ensuring liveness.
Bookmobile answered 25/9, 2017 at 21:47 Comment(0)
B
2

Take a look at the code posted by @xagyg.

Suppose two different threads are waiting for two different conditions:
The first thread is waiting for buf.size() != MAX_SIZE, and the second thread is waiting for buf.size() != 0.

Suppose at some point buf.size() is not equal to 0. JVM calls notify() instead of notifyAll(), and the first thread is notified (not the second one).

The first thread is woken up, checks for buf.size() which might return MAX_SIZE, and goes back to waiting. The second thread is not woken up, continues to wait and does not call get().

Bonanza answered 26/3, 2012 at 21:45 Comment(0)
B
1

notify will notify only one thread which are in waiting state, while notify all will notify all the threads in the waiting state now all the notified threads and all the blocked threads are eligible for the lock, out of which only one will get the lock and all others (including those who are in waiting state earlier) will be in blocked state.

Bendicty answered 22/7, 2014 at 18:25 Comment(0)
U
1

To summarize the excellent detailed explanations above, and in the simplest way I can think of, this is due to the limitations of the JVM built-in monitor, which 1) is acquired on the entire synchronization unit (block or object) and 2) does not discriminate about the specific condition being waited/notified on/about.

This means that if multiple threads are waiting on different conditions and notify() is used, the selected thread may not be the one which would make progress on the newly fulfilled condition - causing that thread (and other currently still waiting threads which would be able to fulfill the condition, etc..) not to be able to make progress, and eventually starvation or program hangup.

In contrast, notifyAll() enables all waiting threads to eventually re-acquire the lock and check for their respective condition, thereby eventually allowing progress to be made.

So notify() can be used safely only if any waiting thread is guaranteed to allow progress to be made should it be selected, which in general is satisfied when all threads within the same monitor check for only one and the same condition - a fairly rare case in real world applications.

Upton answered 11/10, 2015 at 15:46 Comment(0)
B
0

notify() wakes up the first thread that called wait() on the same object.

notifyAll() wakes up all the threads that called wait() on the same object.

The highest priority thread will run first.

Botch answered 5/12, 2011 at 18:49 Comment(4)
In case of notify() it's not exactly "the first thread".Economizer
you cannot predict which one will be chosen by VM. Only God knows.Aili
There's no guarantee who will be the first (no fairness)Ribeiro
It will only wake up the first thread if the OS guarantees that, and it's likely that it doesn't. It really defers to the OS (and its scheduler) to determine which thread to wake.Nellanellda
O
0

When you call the wait() of the "object"(expecting the object lock is acquired),intern this will release the lock on that object and help's the other threads to have lock on this "object", in this scenario there will be more than 1 thread waiting for the "resource/object"(considering the other threads also issued the wait on the same above object and down the way there will be a thread that fill the resource/object and invokes notify/notifyAll).

Here when you issue the notify of the same object(from the same/other side of the process/code),this will release a blocked and waiting single thread (not all the waiting threads -- this released thread will be picked by JVM Thread Scheduler and all the lock obtaining process on the object is same as regular).

If you have Only one thread that will be sharing/working on this object , it is ok to use the notify() method alone in your wait-notify implementation.

if you are in situation where more than one thread read's and writes on resources/object based on your business logic,then you should go for notifyAll()

now i am looking how exactly the jvm is identifying and breaking the waiting thread when we issue notify() on a object ...

Ohaus answered 21/4, 2016 at 18:32 Comment(0)
B
0

While there are some solid answers above, I am surprised by the number of confusions and misunderstandings I have read. This probably proves the idea that one should use java.util.concurrent as much as possible instead of trying to write their own broken concurrent code.

Back to the question: to summarize, the best practice today is to AVOID notify() in ALL situations due to the lost wakeup problem. Anyone who doesn't understand this should not be allowed to write mission critical concurrency code. If you are worried about the herding problem, one safe way to achieve waking one thread up at a time is to:

  1. Build an explicit waiting queue for the waiting threads;
  2. Have each of the thread in the queue wait for its predecessor;
  3. Have each thread call notifyAll() when done.

Or you can use Java.util.concurrent.*, which have already implemented this.

Boarfish answered 28/1, 2017 at 14:3 Comment(1)
in my experience, the use of wait/notify is often used in queue mechanisms where a thread (Runnable implementation) processing the content of a queue. The wait() is then used whenever the queue is empty. And the notify() is called when information is added. --> in such a case there's only 1 thread that ever calls the wait() , then doesn't it look a bit silly to use a notifyAll() if you know there's only 1 waiting thread.Vachell
M
0

Waiting queue and blocked queue

You can assume there are two kinds of queues associated with each lock object. One is blocked queue containing thread waiting for the monitor lock, other is waiting queue containing thread waiting to be notified. (Thread will be put into waiting queue when they call Object.wait).

Each time the lock is available, the scheduler choose one thread from blocked queue to execute.

When notify is called, there will only be one thread in waiting queue are put into blocked queue to contend for the lock, while notifyAll will put all thread in waiting queue into blocked queue.

Now can you see the difference?
Although in both case there will only be one thread get executed, but with notifyAll, other threads still get a change to be executed(Because they are in the blocked queue) even if they failed to contend the lock.

some guidline

I basically recommend use notifyAll all the time althrough there may be a little performance penalty.
And use notify only if :

  1. Any waked thread can make the programe proceed.
  2. performance is important.

For example:
@xagyg 's answer gives a example which notify will cause deadlock. In his example, both producer and consumer are related with the same lock object. So when a producer calls notify, either a producer or a consumer can be notified. But if a producer is woken up it can not make the programe proceed because the buffer is already full.So a deadlock happens.
There are two ways to solve it :

  1. use notifyALl as @xagyg suggests.
  2. Make procuder and consumer related with different lock object and procuder can only wake up consumer, consumer can only wake up producer. In that case, no matter which consumer is waked, it can consumer the buffer and make the programe proceed.
Mightily answered 18/10, 2020 at 3:38 Comment(0)
A
-2

Waking up all does not make much significance here. wait notify and notifyall, all these are put after owning the object's monitor. If a thread is in the waiting stage and notify is called, this thread will take up the lock and no other thread at that point can take up that lock. So concurrent access can not take place at all. As far as i know any call to wait notify and notifyall can be made only after taking the lock on the object. Correct me if i am wrong.

Artificial answered 14/12, 2009 at 8:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.