Question

Hi I was trying to understand wait notify and i see this behaviour in the code that 2 threads are printing statements inside synchronized block on same object.

public class WaitNotifyExample {

/**
 * @param args
 */
public static void main(String[] args) {
    Message msg = new Message("process it");
    Waiter waiter = new Waiter(msg);
    new Thread(waiter,"waiter").start();

    Waiter waiter1 = new Waiter(msg);
    new Thread(waiter1, "waiter1").start();

    Notifier notifier = new Notifier(msg);
    new Thread(notifier, "notifier").start();
    //System.out.println("All the threads are started");

}

}

class Message {
private String msg;

public Message(String str){
    this.msg=str;
}

public String getMsg() {
    return msg;
}

public void setMsg(String str) {
    this.msg=str;
}

}

class Waiter implements Runnable{

private Message msg;

public Waiter(Message m){
    this.msg=m;
}

@Override
public void run() {
    String name = Thread.currentThread().getName();
    synchronized (msg) {
        try{
            System.out.println(name+" waiting to get notified at time:"+System.currentTimeMillis());
            msg.wait();
        }catch(InterruptedException e){
            e.printStackTrace();
        }
        System.out.println(name+" waiter thread got notified at time:"+System.currentTimeMillis());
        //process the message now
        System.out.println(name+" processed: "+msg.getMsg());
    }
}

}
class Notifier implements Runnable {

private Message msg;

public Notifier(Message msg) {
    this.msg = msg;
}

@Override
public void run() {
    String name = Thread.currentThread().getName();
    System.out.println(name+" started");
    try {
        Thread.sleep(1000);
        synchronized (msg) {
            msg.setMsg(name+" Notifier work done");
            //msg.notify();
            msg.notifyAll();
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

}

}

Here is the output of the program:

    -waiter waiting to get notified at time:1393849891481  
    -notifier started  
    -waiter1 waiting to get notified at time:1393849891483  
    -waiter1 waiter thread got notified at time:1393849892483  
    -waiter1 processed: notifier Notifier work done  
    -waiter waiter thread got notified at time:1393849892483  
waiter processed: notifier Notifier work done
Was it helpful?

Solution

Read the Javadoc on Object.wait:

The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor

While a thread is blocked inside msg.wait, it does not own msg's monitor. Any other thread is free to acquire it.

OTHER TIPS

The code is working as intended: no single thread is interfering with the output of your messages, as otherwise (if the stream wasn't synchronized internally) those letters and words would be completely mixed up and print gibberish.

However once you call wait, you put the current thread on hold and release the lock on the monitor, so other threads can print something in the meantime.

And another thing your code demonstrates very well: as timing with threads is undefined, it can happen that at the time notifyAll() is called, one, many or zero threads are actually waiting. Which is one of the common wait/notify issues, if Thread B already called notify before Thread A is even waiting.

In addition please note that synchronized/wait/notify is a very basic "brute force" method of thread synchronization that comes with many pitfalls and isn't very fast either as many threads are usually put on hold. It can be used for basic and simple code, but if you really want to dive into threading, you should not use it, but use the concurrent package and it's classes and features instead. The same code could for example be written using a LinkedBlockingQueue<String> instead of using synchronized.

Ok. I think important point already covered that is wait() release the monitor/lock so other thread can come to synchronized block. But I wanted to add 2 important point. 1. when use wait() don't forget to check for condition when or on which you should wait. You might become victim of spurious wakeup calls. Check this link http://handling-thread.blogspot.co.uk/2012/11/what-is-spurious-wakeup-while-wait-in.html 2. If you are considering wait-notify approach I would suggest go for latest solution for the same approach which is using Condition.await-signal

For your reference I have updated the code by Condition approach.

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class WaitNotifyExample {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Message msg = new Message("process it");
        Waiter waiter = new Waiter(msg);
        new Thread(waiter, "waiter").start();

        Waiter waiter1 = new Waiter(msg);
        new Thread(waiter1, "waiter1").start();

        Notifier notifier = new Notifier(msg);
        new Thread(notifier, "notifier").start();
        //System.out.println("All the threads are started");

    }

}

class Message {
    final Lock lock = new ReentrantLock();
    final Condition msgAvailable = lock.newCondition();

    private String msg = null;

    public Message(String str) {
        this.msg = str;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String str) {
        this.msg = str;
    }

    public void lock() {
        lock.lock();
    }

    public void await() throws InterruptedException {
        msgAvailable.await();
    }

    public void unlock() {
        lock.unlock();
    }

    public void signal() {
        msgAvailable.signal();
    }

    public void signalAll() {
        msgAvailable.signalAll();
    }
}

class Waiter implements Runnable {

    private Message msg;



    public Waiter(Message m) {
        this.msg = m;
    }

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        msg.lock();
            try {
                System.out.println(name + " waiting to get notified at time:" + System.currentTimeMillis() + "   Object: " + msg);
                //You missed while condition which is very important aspect of wait-notify. You can check this link
                //http://handling-thread.blogspot.co.uk/2012/11/what-is-spurious-wakeup-while-wait-in.html
                while(msg.getMsg() == null)
                    msg.await();
                //msg.wait();
                System.out.println(name + " waiter thread got notified at time:" + System.currentTimeMillis() + "   Object: " + msg);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                msg.unlock();
            }
            //process the message now
            System.out.println(name + " processed: " + msg.getMsg());
        }
    }

class Notifier implements Runnable {

    private Message msg;

    public Notifier(Message msg) {
        this.msg = msg;
    }

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        System.out.println(name + " started");
        msg.lock();
        try {
            Thread.sleep(1000);
                msg.setMsg(name + " Notifier work done");
                //msg.notify();
                msg.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            msg.unlock();
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top