5

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();
    }
}
Chris Martin
  • 30,334
  • 10
  • 78
  • 137
Muniyasamy V
  • 81
  • 1
  • 4
  • 9
  • I think this can help you: [Java Threads: Using wait, notify, and notifyAll](https://www.devmedia.com.br/java-threads-utilizando-wait-notify-e-notifyall/29545) – Fabian Brandão Dec 13 '18 at 10:50

6 Answers6

7

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.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • And all that said (which is pretty decent advice) I wouldn't use wait/notify at all. I'd use some classes from the `java.util.concurrent` package: `Lock`, `Semaphore` and `CyclicBarrier` are [all better bets](http://winterbe.com/posts/2015/04/30/java8-concurrency-tutorial-synchronized-locks-examples/) than trying to manage synchronization yourself. – markspace Apr 08 '17 at 03:21
  • @markspace - That's true. But in this case, I suspect that the OP is doing this to try to understand wait / notify. – Stephen C Apr 08 '17 at 03:37
  • And it should also be noted that `Lock`, `Semaphore` and `CyclicBarrier` don't notify a *specific* thread. In fact, they notify (in a sense) *some* thread that is using the concurrency object ... irrespective of its identity. – Stephen C Oct 30 '22 at 07:49
1

To add some points;

Your code is using intrinsic locks. Every object in the JVM has its own lock. This lock has nothing to do with the functionality of the object. Acquiring the lock by itself does nothing (in the absence of further measures like using the synchronized keyword) to prevent other threads from monkeying with the object's contents. Calling notify on a thread does not mean that that particular thread will receive a notification.

As said previously acquiring the lock on Thread objects is discouraged. The join method on Thread uses the intrinsic lock on the thread joined to. If code acquires a lock for different reasons then a thread can be notified for some condition that it may not care about.

The intrinsic lock is a go-between that tells the OS scheduler which threads are waiting. The OS scheduler decides which threads in the wait set for the lock get notified. When a thread calls notify on an object, it is telling the lock on that object to tell the scheduler to choose which waiting thread gets notified. The lock knows which threads are waiting but it doesn't know what condition they're waiting for. (ReentrantLock is a big improvement for this, see the API doc for Condition.)

Of course notifyAll wakes up all the threads in the wait set, but again that is something the lock and the scheduler know. The thread calling notifyAll doesn't know about what threads are waiting. The system is designed intentionally so that threads cannot notify other threads directly.

Yet another thing here is that calling wait with no check for a condition is unreliable. If a thread doesn't happen to have acquired a lock before a notification is made, it misses that notification. If a thread receives a notification, that is no guarantee it will get the lock next, another thread could act and invalidate the state that the notified thread is expecting. Always have some internal state that the current thread can check to verify that the object's state is what the thread is expecting, and make that check as the test in a loop.

For instance if I have a fixed size blocking queue (implemented using a list internally, protecting it from concurrent access using synchronization) where threads try to take something from the queue but block if the queue is empty, the take method could look like:

public synchronized T take() throws InterruptedException {
    while (list.isEmpty()) {
        wait();
    }
    notifyAll();
    return list.remove(0);
}

Once a waiting thread wakes and reacquires the lock, it checks to see if the current situation is what it has been waiting for. Only if that is the case should the thread exit the loop and proceed.

Nathan Hughes
  • 94,330
  • 19
  • 181
  • 276
1

Here you can find out the nice example how to use wait and notify or notifyAll() – Niraj 2 days ago
If you are using notify() instead of notifyAll() it will triger only one thread in wait() state with high priority. If you are using notifyAll() it will triger all the thread which was in wait() state.

   package com.construction.house;

import com.construction.labours.LabourCement;
import com.construction.labours.LabourPainting;
import com.construction.labours.LabourPolishMarbel;

public class House implements Runnable{

    public House() {
        // TODO Auto-generated constructor stub
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        House myHouse = new House();
        LabourCement labourCement = new LabourCement(myHouse,"Cement");
        labourCement.start();

        LabourPainting labourPaining = new LabourPainting(myHouse,"Painter");
        labourPaining.start();

        LabourPolishMarbel labourPolish = new LabourPolishMarbel(myHouse,"PolishMan");
        labourPolish.start();

    }
    boolean isPolished = false,isCemented = false,isPaited = false;

    public synchronized void workAsDemand() throws InterruptedException {
        if (!isPolished) {
            isPolished = true;
            System.out.println(Thread.currentThread().getName()+"--->>Polish in progress");
            wait();
            System.out.println(Thread.currentThread().getName()+"--->>Polish Completed");

        }

        else if (!isPaited) {
            System.out.println(Thread.currentThread().getName()+"--->>Painting house in Progress");
            isPaited = true;
            //notify();
            wait();
            System.out.println(Thread.currentThread().getName()+"--->>Painting house in Completed");

        }

        else if (!isCemented) {
            System.out.println(Thread.currentThread().getName()+"---->>Cemented house");
            isCemented = true;
            notifyAll();

        }


    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        try {
            workAsDemand();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}



package com.construction.labours;

public class LabourCement extends Thread {

    public LabourCement() {
        // TODO Auto-generated constructor stub
    }

    public LabourCement(Runnable arg0) {
        super(arg0);
        // TODO Auto-generated constructor stub
    }

    public LabourCement(String arg0) {
        super(arg0);
        // TODO Auto-generated constructor stub
    }

    public LabourCement(ThreadGroup arg0, Runnable arg1) {
        super(arg0, arg1);
        // TODO Auto-generated constructor stub
    }

    public LabourCement(ThreadGroup arg0, String arg1) {
        super(arg0, arg1);
        // TODO Auto-generated constructor stub
    }

    public LabourCement(Runnable arg0, String arg1) {
        super(arg0, arg1);
        // TODO Auto-generated constructor stub
    }

    public LabourCement(ThreadGroup arg0, Runnable arg1, String arg2) {
        super(arg0, arg1, arg2);
        // TODO Auto-generated constructor stub
    }

    public LabourCement(ThreadGroup arg0, Runnable arg1, String arg2, long arg3) {
        super(arg0, arg1, arg2, arg3);
        // TODO Auto-generated constructor stub
    }


}



package com.construction.labours;

public class LabourPolishMarbel extends Thread {

    public LabourPolishMarbel() {
        // TODO Auto-generated constructor stub
    }

    public LabourPolishMarbel(Runnable arg0) {
        super(arg0);
        // TODO Auto-generated constructor stub
    }

    public LabourPolishMarbel(String arg0) {
        super(arg0);
        // TODO Auto-generated constructor stub
    }

    public LabourPolishMarbel(ThreadGroup arg0, Runnable arg1) {
        super(arg0, arg1);
        // TODO Auto-generated constructor stub
    }

    public LabourPolishMarbel(ThreadGroup arg0, String arg1) {
        super(arg0, arg1);
        // TODO Auto-generated constructor stub
    }

    public LabourPolishMarbel(Runnable arg0, String arg1) {
        super(arg0, arg1);
        // TODO Auto-generated constructor stub
    }

    public LabourPolishMarbel(ThreadGroup arg0, Runnable arg1, String arg2) {
        super(arg0, arg1, arg2);
        // TODO Auto-generated constructor stub
    }

    public LabourPolishMarbel(ThreadGroup arg0, Runnable arg1, String arg2, long arg3) {
        super(arg0, arg1, arg2, arg3);
        // TODO Auto-generated constructor stub
    }

}




package com.construction.labours;

public class LabourPainting extends Thread {

    public LabourPainting() {
        // TODO Auto-generated constructor stub
    }

    public LabourPainting(Runnable arg0) {
        super(arg0);
        // TODO Auto-generated constructor stub
    }

    public LabourPainting(String arg0) {
        super(arg0);
        // TODO Auto-generated constructor stub
    }

    public LabourPainting(ThreadGroup arg0, Runnable arg1) {
        super(arg0, arg1);
        // TODO Auto-generated constructor stub
    }

    public LabourPainting(ThreadGroup arg0, String arg1) {
        super(arg0, arg1);
        // TODO Auto-generated constructor stub
    }

    public LabourPainting(Runnable arg0, String arg1) {
        super(arg0, arg1);
        // TODO Auto-generated constructor stub
    }

    public LabourPainting(ThreadGroup arg0, Runnable arg1, String arg2) {
        super(arg0, arg1, arg2);
        // TODO Auto-generated constructor stub
    }

    public LabourPainting(ThreadGroup arg0, Runnable arg1, String arg2, long arg3) {
        super(arg0, arg1, arg2, arg3);
        // TODO Auto-generated constructor stub
    }

}
Niraj
  • 31
  • 4
  • Here you can find out the nice example how to use wait and notify or notifyAll() – Niraj Mar 08 '19 at 18:56
  • If you are using notify() instead of notifyAll() it will triger only one thread in wait() state with high priority. If you are using notifyAll() it will triger all the thread which was in wait() state. Thanks – Niraj Mar 08 '19 at 18:58
  • Add description to answer, not in comments – mechnicov Mar 08 '19 at 19:18
0

Solution: remove calling object t1.

Change t1.notify() to notify().

סטנלי גרונן
  • 2,917
  • 23
  • 46
  • 68
0
Proper Explanation:

Okay first of all wait(), notify() and notifyAll() methods have to be called over the lock object which are used by threads for synchronization. In your case, you have used synchronization on the method level so JRE takes this as something like:

void methodOne() {
synchronised(this) {
// code you want to execute mutually exclusively.
}
}

so here the monitor lock object is your Shared object itself, and the threads will use this as the monitor object to execute their code mutually exclusively. So now, One of your thread might be in the WAITING STATE in the lock object monitor, So to notify that object you have to call a method notify() or notifyAll() on the lock monitor object(because threads are in the monitor state of the lock object in different STATES) only. So you will say this.notify() or this.notifyAll() on the monitor object only. (If you use any other lock object for synchronization then all these methods get called over that lock object only). notify(): will notify any of the thread which is in WAITING STATE in the lock object monitor. notifyAll(): will notify all the threads which are in WAITING STATE in the lock object monitor. When we call notify() or notifyAll() over the monitor lock object then the threads state gets changed from WAITING to RUNNABLE, as it gets to RUNNABLE STATE for a very short period of time, then the STATE gets changed to BLOCKED STATE because the threads in lock object monitor which just got notify() didn't get the lock object for executing their code -> if the thread which calls the method this.notify() didn't complete its execution after notifying.

0

To communicate specific thread you need make use of thread owner follow below example here exp and singleton are object class

  Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
           synchronized (exp){
               try {
                   Log.e("Thread 1","thread 1 going to waiting state ");
                   exp.wait();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
           synchronized (singleton) {
               singleton.notify();
           }
        }
    });

    Thread t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (exp) {
                Log.e("Thread 2","notified to all thread ");
                exp.notify();
            }
        }
    });
    Thread t3 = new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (singleton){
                try {
                    Log.e("Thread 3","thread 3 going to waiting state ");
                    singleton.wait();
                    Log.e("Thread 3","thread 3 notified");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    });
    t1.start();
    t2.start();
    t3.start();

if you try to notify a thread which owner object is different then it will give error IllegalMonitorState exception while notify you must be care full same object owner must required.