Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between notify() and notifyAll()

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?

like image 962
arjacsoh Avatar asked Dec 12 '22 17:12

arjacsoh


2 Answers

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.

like image 55
Marko Topolnik Avatar answered Dec 24 '22 01:12

Marko Topolnik


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.

like image 26
G. Blake Meike Avatar answered Dec 24 '22 02:12

G. Blake Meike