0

Before I move onto using Condition variables I'm trying to understand object wait principles. I wrote a little code to understand more but its not working as expected.

What is supposed to happen is a Waiter class waits upon thread start. Meanwhile the Notifier class adds some elements to a list using a loop. Once the Notifier has done this it notifies the Waiter which should simply print that it has been notified but i get illegalmonitorstate exception

This is my output

Exception in thread "Waiter Thread" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at tutorials.waitnotify.Waiter.run(Waiter.java:26)
at java.lang.Thread.run(Thread.java:745)
0 [Waiter Thread] DEBUG tutorials.waitnotify.Waiter  - Starting waiter....
2002 [Notifier Thread] DEBUG tutorials.waitnotify.Waiter  - Starting     
notifier...
3005 [Notifier Thread] DEBUG tutorials.waitnotify.Waiter  - Element added [1]
4007 [Notifier Thread] DEBUG tutorials.waitnotify.Waiter  - Element added [2]
5012 [Notifier Thread] DEBUG tutorials.waitnotify.Waiter  - Element added [3]
Exception in thread "Notifier Thread" java.lang.IllegalMonitorStateException
7022 [Notifier Thread] DEBUG tutorials.waitnotify.Waiter  - Object about to    
notify
at java.lang.Object.notify(Native Method)
at tutorials.waitnotify.Notifier.run(Notifier.java:42)
at java.lang.Thread.run(Thread.java:745)

This is the code As you can see I'm trying to synchronise on a common lock object.

public class Notifier implements Runnable {

private static final Logger LOGGER = LoggerFactory.getLogger(Waiter.class);
private List<Integer> list;
private Object commonLock;

public Notifier(Object lock) {
    this.list = new ArrayList<>();
    this.commonLock = lock;
}

public void run() {
    LOGGER.debug("Starting notifier....");
    synchronized (commonLock) {
        for (int i = 1; i <= 3; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ie) {
                LOGGER.debug("Interrupted");
            }
            list.add(i);
            LOGGER.debug("Element added [{}]", i);
        }
        LOGGER.debug("About to notify");
        notify();
    }
}
}

public class Waiter implements Runnable {

private static final Logger LOGGER = LoggerFactory.getLogger(Waiter.class);
private final Object commonLock;

public Waiter(Object lock) {
    this.commonLock = lock;
}

public void run() {
    LOGGER.debug("Starting waiter....");
    synchronized (commonLock) {
        try {
            wait(10000);
        } catch (InterruptedException ie) {
            LOGGER.debug("Interrupted");
        }
    }
    LOGGER.debug("Object been notified");
}
}

public class WaiterNotifierMain {

public static void main(String[] args) {
    BasicConfigurator.configure();

    Object lock = new Object();
    Waiter waiter = new Waiter(lock);
    Notifier notifier = new Notifier(lock);

    Thread waiterThread = new Thread(waiter);
    Thread notifierThread = new Thread(notifier);

    notifierThread.setName("Notifier Thread");
    waiterThread.setName("Waiter Thread");
    waiterThread.start();
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    notifierThread.start();
}
}

Any pointers would be appreciated. Thanks in advance

1 Answer 1

3

You should do

  • commonLock.wait(10000)
  • commonLock.notify()

You get an exception because you're waiting and notifying on "this". And you didn't synchronize on "this".

You might consider using notifyAll() instead of notify():

If you plan to have multiple Waiter threads, keep in mind that notify() will only wake up one Waiter thread at a time. If you want to wake up ALL Waiter threads at once, you should use the notifyAll() method instead.

Even if know that you will never have more than one Waiter thread, I consider it best practice to use notifyAll() instead of notify(), since the Notifier object doesn't know how many threads are listening on the object...

5
  • "It's also better to use notifyAll() instead of notify()." That's a very blanket statement with no justification in the answer...
    – Jon Skeet
    Commented Jun 11, 2015 at 9:23
  • Cheers @Stefan that worked. I only used notify as i had one thread waiting.
    – L-Samuels
    Commented Jun 11, 2015 at 9:37
  • @Jon you are right... Indeed notify() also works if you have only one thread waiting for the notification. If you have multiple Waiters, only one will be notified. If this is the required behaviour then that's fine. If it doesn't matter (because you know, you will only have one Waiter thread anyway), I still consider it best practice to use the notifyAll(), since the Waiter object doesn't know how many objects are waiting for the lock object. By using notifyAll(), you are sure that the notification is arrived by the Waiter, no matter who else is waiting on the lock. Commented Jun 11, 2015 at 10:02
  • @StefanBangels: Well, if you have multiple waiters and you want to wake them all up. It's entirely feasible that you only want to wake one waiter up at a time. I don't think it's nearly as simple as just "default to notifyAll".
    – Jon Skeet
    Commented Jun 11, 2015 at 10:02
  • @Jon you are right... I didn't know the context, and therefor shouldn't have suggested to use notifyAll() instead of notify()... I will update my answer. Commented Jun 11, 2015 at 10:08

Not the answer you're looking for? Browse other questions tagged or ask your own question.