Reputation: 208
I am trying to use wait() and notify() on a class to notify the waiting thread but the scenario is whoever go first into the synchronized block will wait for other to print some values and notify the waiting thread. but the waiting thread is keep waiting. what am doing wrong.
public class MyRunnableClass implements Runnable {
public static boolean transfer = false;
public static boolean isAnyThreadWaiting = false;
int a=10;
@Override
public void run() {
// TODO Auto-generated method stub
synchronized(this) {
System.out.println("I am Thread : "+Thread.currentThread().getName()+" and I first occuipied block");
try {
if(isAnyThreadWaiting)
MyRunnableClass.transfer=true;
if(!MyRunnableClass.transfer&&!isAnyThreadWaiting) {
System.out.println("I am Thread : "+Thread.currentThread().getName()+" and I am going to wait");
while(!MyRunnableClass.transfer) {
isAnyThreadWaiting=true;
this.wait();
}
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for(int i=0; i<a;i++) {
System.out.println("I am Thread : "+Thread.currentThread().getName()+" Value of a is : "+i );
}
a=0;
isAnyThreadWaiting=false;
this.notify();
}
}
public static void main(String [] args) throws InterruptedException {
MyRunnableClass runnable1= new MyRunnableClass();
Thread thread1=new Thread(runnable1,"t1");
Thread thread2=new Thread(runnable1,"t2");
thread1. start();
thread2. start();
}
}
Upvotes: 1
Views: 158
Reputation: 1367
I have debugged your code and found the reason:
a=0;
Please, remove this code and you will see the output of both threads:
I am Thread : t1 and I first occuipied block
I am Thread : t1 and I am going to wait
I am Thread : t2 and I first occuipied block
I am Thread : t2 Value of a is : 0
I am Thread : t2 Value of a is : 1
I am Thread : t2 Value of a is : 2
I am Thread : t2 Value of a is : 3
I am Thread : t2 Value of a is : 4
I am Thread : t2 Value of a is : 5
I am Thread : t2 Value of a is : 6
I am Thread : t2 Value of a is : 7
I am Thread : t2 Value of a is : 8
I am Thread : t2 Value of a is : 9
I am Thread : t1 Value of a is : 0
I am Thread : t1 Value of a is : 1
I am Thread : t1 Value of a is : 2
I am Thread : t1 Value of a is : 3
I am Thread : t1 Value of a is : 4
I am Thread : t1 Value of a is : 5
I am Thread : t1 Value of a is : 6
I am Thread : t1 Value of a is : 7
I am Thread : t1 Value of a is : 8
I am Thread : t1 Value of a is : 9
P.S. Second thread in your example actually doesn't go to the wait() state.
But because you set a to 0 by the second thread, the first thread skips this cycle:
for(int i=0; i<a;i++) {
System.out.println("I am Thread : "+Thread.currentThread().getName()+" Value of a is : "+i );
}
That's why you don't see the output by the first thread. But it isn't stuck in the wait() state.
Upvotes: 1
Reputation: 1367
Changes made to static variables in one thread are not visible to the other thread. Therefore, for both threads, it is always transfer == false and isAnyThreadWaiting == false.
This means that both threads go to "wait()" block and stuck there forever.
Because you are trying to synchronize on the static variables, you would have to use synchronized static method.
See more details here: How to synchronize a static variable among threads running different instances of a class in Java?
But the simpler solution would be not to use static variables at all. In your case, you use the same object for both threads, so making variables static is not necessary anyway:
private boolean transfer = false;
private boolean isAnyThreadWaiting = false;
The complete solution should look like this:
public class MyRunnableClass implements Runnable {
private boolean transfer = false;
private boolean isAnyThreadWaiting = false;
int a=10;
@Override
public void run() {
// TODO Auto-generated method stub
synchronized(this) {
System.out.println("I am Thread : "+Thread.currentThread().getName()+" and I first occuipied block");
try {
if(isAnyThreadWaiting)
transfer=true;
if(!transfer && !isAnyThreadWaiting) {
System.out.println("I am Thread : "+Thread.currentThread().getName()+" and I am going to wait");
while(!transfer) {
isAnyThreadWaiting=true;
this.wait();
}
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for(int i=0; i<a;i++) {
System.out.println("I am Thread : "+Thread.currentThread().getName()+" Value of a is : "+i );
}
a=0;
isAnyThreadWaiting=false;
this.notify();
}
}
public static void main(String [] args) throws InterruptedException {
MyRunnableClass runnable1= new MyRunnableClass();
Thread thread1=new Thread(runnable1,"t1");
Thread thread2=new Thread(runnable1,"t2");
thread1. start();
thread2. start();
}
}
Upvotes: 0
Reputation: 70267
synchronized(this)
this
is the same in both of your threads, since you used the same Runnable
instance. synchronized
ensures that two threads can't be inside the block at the same time. Which means one thread is sitting at the beginning of the synchronized
block and the other is sitting at wait
. You need to narrow your synchronization down to the places you actually use shared state, i.e. only synchronized(this)
the code that actually references (reads or writes) the variables that both threads need.
Upvotes: 2