Java Multithreading – Postmortem of notify(), notifyAll(), and wait()
notify() or notifyAll(), and wait()
notify() or notifyAll(), and wait() must be in a synchronized block for the object you are waiting on. So the following codes are correct;
public synchronized void method(){
wait(); //or this.wait();
}
public void method(){
synchronized(this){
wait(); //or this.wait();
}
}
public void method(){
synchronized(a){
a.wait();
}
}
public synchronized void method(){
synchronized(a){
wait();
}
}
- But following code generates run time exception java.lang.IllegalMonitorStateException
- If you change synchronized object inside synchronized block notify() or notifyAll(), and wait() will give run time exception java.lang.IllegalMonitorStateException.
- Thread.sleep(1000) asks current thread to wait till specified period. It doesn’t bother about locks and all. So it doesn’t releases lock. On the other hand, wait() releases lock and acquires lock again once notify() or notifyAll() get called on same object or specified time is over.
- Thread A: enters into monitor of a.
- Thread B: waits to get entered into monitor of a.
- Thread A: meets to a.wait(5000). So it releases lock on a.
- Thread B: enters into monitor a. waits and acquires lock on a.
- Thread A: try to acquire released lock. But it is already acquired by Thread B. So it waits.
- Thread B: changes value of a.
- Thread A: acquire lock on a. It prints new value of a.
- On the other hand, if I use Thread.sleep(n) in place of wait(n)
- The problem with calling wait() and notify() on the empty string, or any other constant string is, that the JVM/Compiler internally translates constant strings into the same object. That means, that even if you have two different MyWaitNotify instances, they both reference the same empty string instance. This also means that threads calling wait() on the first MyWaitNotify instance risk being awakened by notify() calls on the second MyWaitNotify instance.
- If there are multiple threads waiting on same object, notify() can awake any thread randomly. It arises the condition that some threads never get awaken and some always get awaken. This situation is called Starvation. Sometimes some greedy threads don’t release resources (call sleep() instead of wait() etc). It also force other threads to wait. Some threads increase their priority to get served first to CPU, it also force low priority threads to wait for long. These all conditions where any thread need to wait very long is called Starvation.
public void method(){
synchronized(a){
wait();
}
}
public void method(){
synchronized(a){
synchronized(this){
wait(n);
}
}
}
public synchronized void method(){
synchronized(a){
wait(n);
}
}
synchronized(a){
a = 55;
a.wait();
}
In above example, you are waiting on new copy of a while synchronizing on old copy of a. Below code doesn’t generate exception.
synchronized(a){
a.wait();
a = 55;
}
Because you are waiting on same copy of a, you are synchronizing on. Then you are changing a.
public void acquire(){
synchronized(a){
print("acquire()");
try{
a.wait(5000);
print("I have awoken");
print("" + a);
}catch(Exception e){
e.printStackTrace();
}
}
print("Leaving acquire()");
}
public void modify(int n){
print("Entered in modify");
synchronized(a){
try{
a.wait(5000);
this.a=n;
print("new value" + a);
}catch(Exception e){
e.printStackTrace();
}
}
}
Output:
2012-03-06 19:51:27.969 :: A: acquire()
2012-03-06 19:51:27.969 :: B: Entered in modify
2012-03-06 19:51:32.992 :: B: new value97
2012-03-06 19:51:32.992 :: A: I have awoken
2012-03-06 19:51:32.992 :: A: 97
2012-03-06 19:51:32.992 :: A: Leaving acquire()
Explanation:
public void acquire(){
synchronized(a){
print("acquire()");
try{
//a.wait(5000);
Thread.sleep(5000);
print("I have awoken");
print("" + a);
}catch(Exception e){
e.printStackTrace();
}
}
print("Leaving acquire()");
}
Output:
2012-03-06 20:02:39.395 :: A: acquire()
2012-03-06 20:02:39.395 :: B: Entered in modify
2012-03-06 20:02:44.418 :: A: I have awoken
2012-03-06 20:02:44.418 :: A: 10
2012-03-06 20:02:44.418 :: A: Leaving acquire()
2012-03-06 20:02:49.427 :: B: new value97
Explanation
When Thread A meets to sleep(n) it doesn’t release lock.
Read How Nested Monitor can cause DeadLock for a cause of wait().
views


No Comments