How to notify a specific thread in Java

Muniyasamy V picture Muniyasamy V · Apr 8, 2017 · Viewed 13k times · Source

How I can call a particular thread in inter-thread communication?

In the program below I have two threads t1 and t2.

When I call t1.notify() it raises:

Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at Shared.methodTwo(NotifyThread.java:43)
    at Thread2.run(NotifyThread.java:77)
Error 

class Shared {

    Thread1 t1 ;
    Thread2 t2 ;

    void ThreadInit( Thread1 t1 , Thread2 t2 ) {
        this.t1 = t1 ;
        this.t2 = t2 ;
    }

    synchronized void methodOne()
    {
        Thread t = Thread.currentThread();

        System.out.println(t.getName()+" is relasing the lock and going to wait");

        try
        {
            wait();        //releases the lock of this object and waits
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }

        System.out.println(t.getName()+" got the object lock back and can continue with it's execution");
    }

    synchronized void methodTwo()
    {
        Thread t = Thread.currentThread();

        try
        {
            Thread.sleep(5000);
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }

        t1.notify();     

        System.out.println("A thread which is waiting for lock of this object is notified by "+t.getName());
    }
    }

    class Thread1 extends Thread 
    {
    Shared s ;
    Thread1( Shared s ) {

        this.s = s ;
    }

    public void run()
            {
                s.methodOne();   //t1 calling methodOne() of 's' object
            }

    } 

    class Thread2 extends Thread {
         Shared s ;
    Thread2( Shared s ) {

        this.s = s ;

    }

    public void run()
            {
                s.methodTwo();   //t1 calling methodOne() of 's' object
            }


    }
    public class NotifyThread 
    {
    public static void main(String[] args)
    {
        final Shared s = new Shared();

        Thread1 t1 = new Thread1(s) ;
        Thread2 t2 = new Thread2(s) ;

        s.ThreadInit(t1,t2) ;

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

Answer

Stephen C picture Stephen C · Apr 8, 2017

You don't / can't notify a specific thread. You call notify() on a lock object. This wakes up one of the threads1 that is waiting on the lock. In your case, the lock object is a Thread ... which rather confuses the picture. However, see below.

But your problem (the IllegalMonitorStateException) happens because the thread doing the notifying (i.e. the current thread) does not hold the lock. It is a (hard) requirement that the current thread must hold the lock when it notifies a lock.

For more details, read the javadocs for Object.wait(timeout) or (for example) this: http://howtodoinjava.com/core-java/multi-threading/how-to-work-with-wait-notify-and-notifyall-in-java/

1 - If multiple threads are waiting on your lock, one thread is chosen "randomly" by the scheduler. Alternatively notifyAll will wake up all of the waiting threads.


I would NOT use a Thread object as a lock object. It will possibly work, but there is also a chance that something else (maybe something in the runtime system) is also locking / waiting / notifying the Thread objects. Then things would get very confusing.

(Indeed, read the javadoc for Thread.join(long) !)

It is BETTER to create lock objects specifically for this purpose; e.g.

private final Object lock = new Object();

Also, writing classes that extend Thread is usually a bad idea. It is usually better to implement the Runnable interface, instantiate it, and pass the instance as a parameter to the Thread constructor; e.g.

Thread t = new Thread(new Runnable() {
    public void run() {
        System.out.println("Hello world");
    }});
t.start();

One advantage of implementing Runnable rather than extending Thread is that you can use your code more easily with something that manages the thread life cycles for you; e.g. an ExecutorService, a fork-join thread pool or a classic thread pool.

A second one is that light-weight thread logic can be implemented concisely as an anonymous class ... as in my example.