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.9k12 gold badges83 silver badges142 bronze badges
asked Apr 8, 2017 at 2:02
1

6 Answers 6

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.

answered Apr 8, 2017 at 2:19
Sign up to request clarification or add additional context in comments.

3 Comments

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 than trying to manage synchronization yourself.
@markspace - That's true. But in this case, I suspect that the OP is doing this to try to understand wait / notify.
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.
2

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.

answered Apr 8, 2017 at 3:28

Comments

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
 }
}
answered Mar 8, 2019 at 18:55

3 Comments

Here you can find out the nice example how to use wait and notify or notifyAll()
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
Add description to answer, not in comments
0

Solution: remove calling object t1.

Change t1.notify() to notify().

groenhen
3,02725 gold badges51 silver badges69 bronze badges
answered Oct 8, 2020 at 16:46

Comments

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.

answered Jul 11, 2022 at 15:37

Comments

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.

answered Oct 30, 2022 at 6:58

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.