ए भाई Think ज़रा हटके
Note: amtyThumb must be installed for new version of amty thumb post/recent

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();
		}
	}
  1. But following code generates run time exception java.lang.IllegalMonitorStateException
  2. 	public void method(){
    		synchronized(a){
    			wait();
    		}
    	}
    
    	public void method(){
    		synchronized(a){
    			synchronized(this){
    				wait(n);
    			}
    		}
    	}
    
    	public synchronized void method(){
    		synchronized(a){
    			wait(n);
    		}
    	}
    
  3. If you change synchronized object inside synchronized block notify() or notifyAll(), and wait() will give run time exception java.lang.IllegalMonitorStateException.
  4. 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.

  5. 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.
  6. 		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:

    1. Thread A: enters into monitor of a.
    2. Thread B: waits to get entered into monitor of a.
    3. Thread A: meets to a.wait(5000). So it releases lock on a.
    4. Thread B: enters into monitor a. waits and acquires lock on a.
    5. Thread A: try to acquire released lock. But it is already acquired by Thread B. So it waits.
    6. Thread B: changes value of a.
    7. Thread A: acquire lock on a. It prints new value of a.
  7. On the other hand, if I use Thread.sleep(n) in place of wait(n)
  8. 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.

  9. 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.
  10. 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.

Read How Nested Monitor can cause DeadLock for a cause of wait().

Amit Gupta

Hey! this is Amit Gupta (amty). By profession, I am a Software Eng. And teaching is my passion. Sometimes I am a teacher, as you can see many technical tutorials on my site, sometimes I am a poet, And sometime just a friend of friends...

164
views


To book below area mail me




captcha

You can follow any responses to this entry through the RSS 2.0 feed.