4

I know that similar questions have been discussed in this site, but I have not still got further by their aid considering a specific example. I can grasp the difference of notify() and notifyAll() regarding Thread "awakeining" in theory but I cannot perceive how they influence the functionality of program when either of them is used instead of the other. Therefore I set the following code and I would like to know what is the impact of using each one of them. I can say from the start that they give the same output (Sum is printed 3 times).

How do they differ virtually? How could someone modify the program, in order for the applying notify or notifyAll to play a crucial role to its functionality (to give different results)?

Task:

class MyWidget implements Runnable {
private List<Integer> list;
private int sum;

public MyWidget(List<Integer> l) {
    list = l;
}

public synchronized int getSum() {
    return sum;
}

@Override
public void run() {
    synchronized (this) {
        int total = 0;
        for (Integer i : list)
            total += i;

        sum = total;

        notifyAll();
    }
}

}

Thread:

public class MyClient extends Thread {
MyWidget mw;

public MyClient(MyWidget wid) {
    mw = wid;
}

public void run() {
    synchronized (mw) {
        while (mw.getSum() == 0) {
            try {
                mw.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("Sum calculated from Thread "
                + Thread.currentThread().getId() + " : " + mw.getSum());
    }
}

public static void main(String[] args) {
    Integer[] array = { 4, 6, 3, 8, 6 };
    List<Integer> integers = Arrays.asList(array);

    MyWidget wid = new MyWidget(integers);

    Thread widThread = new Thread(wid);
    Thread t1 = new MyClient(wid);
    Thread t2 = new MyClient(wid);
    Thread t3 = new MyClient(wid);

    widThread.start();
    t1.start();
    t2.start();
    t3.start();
}

}

UPDATE: I write it explicitly. The result is the same whether one uses notify or notifyAll: Sum calculated from Thread 12 : 27 Sum calculated from Thread 11 : 27 Sum calculated from Thread 10 : 27

Therefore my question: What is the difference?

arjacsoh
  • 8,932
  • 28
  • 106
  • 166
  • Unfortunately all the provided answers focus on the difference between the two methods in theory and javadocs. My question is why the above program does give the same results with either of two methods (inconsistent with the theory). I have just noticed that when the while loop aroun wait is removed, only one thread is notified when using the notify method and the others wait forever. But I still cannot find why this while loop serves the notification of the other threads. – arjacsoh Feb 17 '13 at 21:42

5 Answers5

11

The difference is subtler than your example aims to provoke. In the words of Josh Bloch (Effective Java 2nd Ed, Item 69):

... there may be cause to use notifyAll in place of notify. Just as placing the wait invocation in a loop protects against accidental or malicious notifications on a publicly accessible object, using notifyAll in place of notify protects against accidental or malicious waits by an unrelated thread. Such waits could otherwise “swallow” a critical notification, leaving its intended recipient waiting indefinitely.

So the idea is that you must consider other pieces of code entering wait on the same monitor you are waiting on, and those other threads swallowing the notification without reacting in the designed way.

Other pitfalls apply as well, which can result in thread starvation, such as that several threads may wait for different conditions, but notify always happens to wake the same thread, and the one whose condition is not satisfied.

Even though not immediately related to your question, I feel it is important to quote this conclusion as well (emphasis by original author):

In summary, using wait and notify directly is like programming in “concurrency assembly language,” as compared to the higher-level language provided by java.util.concurrent. There is seldom, if ever, a reason to use wait and notify in new code. If you maintain code that uses wait and notify, make sure that it always invokes wait from within a while loop using the standard idiom. The notifyAll method should generally be used in preference to notify. If notify is used, great care must be taken to ensure liveness.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • 1
    +1 nice answer. However, I always feel like `notifyAll()` is used far too often to make up for sloppy programming. The idea of rogue code calling wait on an inappropriate object seems far fetched to me. – Gray Feb 17 '13 at 19:03
  • 1
    @Gray At many places in Effective Java I find overly defensive thinking, this would be an instance. One should use a private monitor, anyway, and most scenarios involve all threads waiting on the same condition. – Marko Topolnik Feb 17 '13 at 19:09
  • 1
    Agreed. Even when all of my thread are waiting on the same condition, I _rarely_ want them all to awake at the same time. – Gray Feb 17 '13 at 19:21
  • @Gray: right: you don't want them all to proceed. The usual problem, though, is that java chooses randomly and may not pick a thread whose wait conditions have been met. As I suggest below (and I'm just channeling J.B.) best practice is to wait in a loop, on a condition and use notifyAll. – G. Blake Meike Feb 17 '13 at 19:42
  • That's not really correct @G.BlakeMeike but is a common misconception. Spurious interrupts _do_ happen but they are extremely rare. What is _much_ more likely is bad coding. See my answer here: http://stackoverflow.com/a/2960811/179850 – Gray Feb 17 '13 at 19:46
  • @Gray: That's a nice answer! My comment, though, has nothing to do with spurious interrupts and is correct: In response to a notify() on a given lock, Java chooses a random thread waiting on that lock to restart. If several threads are waiting on the same lock, for different restart conditions, you can't count on Java choosing to restart the one that can make forward progress. – G. Blake Meike Feb 17 '13 at 19:54
  • @G.BlakeMeike To be precise, Java doesn't choose a random thread; it just deliberately makes no guarantees which thread it will choose. The typical underlying implementation will in fact make a very non-random choice: the head of the wait *queue*, as opposed to JLS's wait *set*. – Marko Topolnik Feb 17 '13 at 19:59
  • @Marko Topolnik. Yep, agree completely: "The choice is arbitrary and occurs at the discretion of the implementation". I would only add that, from the point of view of an application developer, this is a lot like saying "random". – G. Blake Meike Feb 17 '13 at 20:03
  • @G.BlakeMeike I'd say it's worse than implied by "random" because the nonrandom choice may result in starvation where a truly random choice wouldn't. – Marko Topolnik Feb 17 '13 at 20:04
  • @G.BlakeMeike The best mental model is "Java may always choose the one thread you'd want it not to"---and code defensively against that scenario :) – Marko Topolnik Feb 17 '13 at 20:06
2

This is made clear in all sorts of docs. The difference is that notify() selects (randomly) one thread, waiting for a given lock, and starts it. notifyAll() instead, restarts all threads waiting for the lock.

Best practice suggests that threads always wait in a loop, exited only when the condition on which they are waiting is satisfied. If all threads do that, then you can always use notifyAll(), guaranteeing that every thread whose wait condition has been satisfied, is restarted.

Edited to add hopefully enlightening code:

This program:

import java.util.concurrent.CountDownLatch;

public class NotifyExample {
    static final int N_THREADS = 10;
    static final char[] lock = new char[0];
    static final CountDownLatch latch = new CountDownLatch(N_THREADS);

    public static void main(String[] args) {
        for (int i = 0; i < N_THREADS; i++) {
            final int id = i;
            new Thread() {
                @Override public void run() {
                    synchronized (lock) {
                        System.out.println("waiting: " + id);
                        latch.countDown();
                        try { lock.wait(); }
                        catch (InterruptedException e) {
                            System.out.println("interrupted: " + id);
                        }
                        System.out.println("awake: " + id);
                    }
                }
            }.start();
        }

        try { latch.await(); }
        catch (InterruptedException e) {
            System.out.println("latch interrupted");
        }
        synchronized (lock) { lock.notify(); }
    }
}

produced this output, in one example run:

waiting: 0
waiting: 4
waiting: 3
waiting: 6
waiting: 2
waiting: 1
waiting: 7
waiting: 5
waiting: 8
waiting: 9
awake: 0

None of the other 9 threads will ever awaken, unless there are further calls to notify.

G. Blake Meike
  • 6,615
  • 3
  • 24
  • 40
  • Ok, that is clear, but my question comes from the fact that after using notify all Threads are excecuted, not only the unique Thread that receives the notification (as expected according the definition). Despite only one Thread is notified, the others perfom their task as well. So what is the difference? Does it consist merely in what selects the Thread to run (JVM or scheduler id I understood well) ? – arjacsoh Feb 17 '13 at 19:04
  • You say: "after using notify, all Threads are executed". That is not true. Only *one* of the threads gets started. The others do not perform their tasks until they, too, are notified. – G. Blake Meike Feb 17 '13 at 19:30
  • Oh. Not sure if I understand that condition @G.BlakeMeike. If they are waiting on a condition then I can only assume that they need it to continue. If you need all threads to wake up then `notifyAll()` is fine but typically all but one go right back to sleep. – Gray Feb 17 '13 at 19:57
  • @Gray: "but typically all but one go right back to sleep" Yes! Exactly! – G. Blake Meike Feb 17 '13 at 19:59
  • Right, exactly. I hate that model @G.BlakeMeike. :-) – Gray Feb 17 '13 at 20:00
  • @G.BlakeMeike: When I try the same code with notify instead of notifyAll, each Thread prints individually its result (as they do with notifyAll). That 's the point of my question. Are they notified all one after one? So, what is the difference compared with notifyAll? – arjacsoh Feb 17 '13 at 20:44
  • @arjacsoh: Not sure what your code looks like; no room here to post code. What Gray, Marko and I all point out is that that is *not* the case. If N threads wait on monitor M (e.g., `synchronized(M) { M.wait(); }`) and the code then calls M.notify(), only *one* thread will start running: N-1 will not. In your case, apparently, something else is waking those other threads. – G. Blake Meike Feb 17 '13 at 21:01
  • @G.BlakeMeike: Can you copy the code, change the notifyAll to notify and present your result? I have tried a couple of times and the result is (WITH NOTIFY): Sum calculated from Thread 12 : 27 Sum calculated from Thread 11 : 27 Sum calculated from Thread 10 : 27 – arjacsoh Feb 17 '13 at 21:07
  • Edited to add demonstrative code. If you need to adjust it to hand in for some class, you'll have to do it yourself ;-) – G. Blake Meike Feb 17 '13 at 23:59
0

notify wakes (any) one thread in the wait set, notifyAll wakes all threads in the waiting set. notifyAll should be used most of the time. If you are not sure which to use, then use notifyAll.

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.

Javadocs on notify.

Javadocs on notifyAll.

syb0rg
  • 8,057
  • 9
  • 41
  • 81
0

Once only one thread is waiting to sum to not be zero, there is no difference. If there are several threads waiting, notify will wake up only one of them, and all the other will wait forever.

Run this test to better understand the difference:

public class NotifyTest implements Runnable {
    @Override
    public void run ()
    {
        synchronized (NotifyTest.class)
        {
            System.out.println ("Waiting: " + this);

            try
            {
                NotifyTest.class.wait ();
            }
            catch (InterruptedException ex)
            {
                return;
            }

            System.out.println ("Notified: " + this);
        }
    }

    public static void main (String [] args) throws Exception
    {
        for (int i = 0; i < 10; i++)
            new Thread (new NotifyTest ()).start ();

        Thread.sleep (1000L); // Let them go into wait ()

        System.out.println ("Doing notify ()");

        synchronized (NotifyTest.class)
        {
            NotifyTest.class.notify ();
        }

        Thread.sleep (1000L); // Let them print their messages

        System.out.println ("Doing notifyAll ()");

        synchronized (NotifyTest.class)
        {
            NotifyTest.class.notifyAll ();
        }
    }
}
Mikhail Vladimirov
  • 13,572
  • 1
  • 38
  • 40
  • Can you explain this in more detail based on the particular code. Do t1, t2, t3 not wait for the sum? Why only one? – arjacsoh Feb 17 '13 at 21:26
0

I found what is going on with my program. The three Threads print the result even with the notify(), because they do not manage to enter the waiting state. The calculation in the widThread is performed quickly enough to preempt the entering of the other Threads in the waiting state, since it depends on the condition mw.getSum() == 0 (while loop). The widThread calculates the sum, so that the remaining Threads do not ever "see" its value as 0. If the while loop is removed and the start of widThread comes after the start of the other Threads, then by notify() only one Thread prints the result and the others are waiting forever, as the theory and the other answers indicate.

eebbesen
  • 5,070
  • 8
  • 48
  • 70
arjacsoh
  • 8,932
  • 28
  • 106
  • 166