Saturday, October 23, 2010

Java - Wait And NotifyAll Example

This post will explain the basics of Java's concept of Waiting for a Object and getting Notified when some flag/state being monitored is changed.

public class WaitAndNotifyAll {

    private static final String LOCK_OBJECT = "LockObject";
   
    private static Boolean flag = false;
   
    public static String getLockObject()
    {
        return LOCK_OBJECT;
    }
   
    public static void setFlagState( boolean flagNewState )
    {
        flag = Boolean.valueOf(flagNewState);
        if( flag == false )
        {
            synchronized ( LOCK_OBJECT ) {
                LOCK_OBJECT.notifyAll();
            }
        }
    }
   
    public static boolean isFlagSet()
    {
        return flag.booleanValue();
    }
   
    public static void main(String[] args)
    {
        System.out.println("Main Thread Started");
        WaitAndNotifyAll.setFlagState(true);
        for( int i = 1; i <= 3; i++ )
        {
            Thread thread = new WaitingThread();
            thread.setName(String.valueOf(i));
            thread.start();
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        WaitAndNotifyAll.setFlagState(false);
        System.out.println("Main Thread Completed");
    }
   
}

class WaitingThread extends Thread
{
    public void run()
    {
        final String threadName = this.getName();
        System.out.println(threadName + " started");
        Object lockObject = WaitAndNotifyAll.getLockObject();
        while( WaitAndNotifyAll.isFlagSet() )
        {
            synchronized (lockObject) {
                try {
                    lockObject.wait();
                } catch (InterruptedException e) {
                    System.err.println(threadName + ": Exception: " + e.getLocalizedMessage());
                }
            }
        }
        System.out.println(threadName + " completed");
    }
}


Here, WaitAndNotifyAll is the Main Class that has the flag being monitored and a Lock Object for other threads to wait for - and get notified when the flag is Reset.

Since, the LockObject, on which a wait call is made, should not be changed - for the notify or notifyAll call to work we made the LockObject final. WaitingThread can get the reference of LockObject by using the method getLockObject.

The flag which is being monitored can be set/reset using the method setFlagState and the value can be read by using the method isFlagSet.

The MainThread set the flag to TRUE state so that any calls to wait on LockObject will be notified when the flag is set to FALSE. It starts 3 WaitingThread objects and starts them - sleep for a while and resets the flag.

WaitingThreads which are waiting on LockObject will be notified when the flag is reset and they wake up and prints Completed message.

The difference between notify and notifyAll methods is that notify will wake the first thread that called wait on the object whereas notifyAll will wake up all the threads that have called wait on the object - highest priority thread / the thread that got the synchronization lock for that object will run first.

IMPORTANT: Always invoke wait inside a loop that tests for the condition being waited for. Don't assume that the interrupt was for the particular condition you were waiting for, or that the condition is still true.

No comments:

Post a Comment