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();
}
}
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.