Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Wiki Markup
The methods {{notify()}} and {{notifyAll()}} are used to waken waiting thread(s). These methods must be called from a block that holds the same object lock as the waiting thread(s). The method {{notify()}} is deceptive in most cases unless all of the following conditions hold:
[Concurrency
 \[[Goetz 06|AA. Java References#Goetz 06]\]

  • Only one condition predicate is used with the locked object. Also, each thread must execute the same code after waking up from a wait.
  • Only one thread must wake up on the notify signal. This is contingent on the condition predicate, in that, only one predicate must fulfill the condition and allow the thread to proceed.

These are typically true when only one thread is waiting. Otherwise, if either doesn't hold, incorrect program behavior may result.

Noncompliant Code Example

This noncompliant example demonstrates a violation of liveness. A lock is held on a shared object list and three threads are started. Two condition predicates, one checking whether the buffer has zero elements and another that checks if the buffer is full with ten elements, have been used. Initially the buffer is neither full nor empty. Conditions are created so that first the buffer becomes empty and thread 1 goes into wait state, followed by thread 2.

Note that when thread 2 goes into wait, the condition predicate of thread 1 has become false. When notify() is invoked by thread 3, it can be delivered to either thread 1 or thread 2 depending on the JVM. If thread 1 is chosen, it's condition turns out to be false. Even though this notify was meant for thread 2 (whose condition is on the other hand, true) thread 1 wakes up on its false condition.

Code Block
bgColor#FFcccc
public class MissedSignal implements Runnable{
  private static LinkedList list = new LinkedList();
  private static int buffer_count = 5;
  private int number;      //selects function based on thread number	
        
  public MissedSignal(int number) {
    this.number = number;
  }
        
  public  void run (){
    synchronized(list) {
      try {
            if(number == 1) {	  
              System.out.println("Thread 1 started..."); 
              while(buffer_count == 0) { 
      	        System.out.println("Beginning wait() Thread 1...");	
      	        list.wait();		  
      	        System.out.println("Thread 1 got notified this time...");
      	    }  
      	    System.out.println("Exiting because Thread 1 condition is false...");	
      	  }  
      	  else if(number == 2) {  	    		  
      	    System.out.println("Thread 2...");
      	    while(buffer_count > 0) {	
      	      System.out.println("Beginning wait() Thread 2...");	
      	      list.wait();   	    		    	  
      	      System.out.println("Thread 2 got notified this time...");
      	    }
      	    System.out.println("Exiting because the thread 2 condition is false...");
      	  }
      	  else if(number == 3) {
      	    Thread.sleep(2000);	   		    			   
            list.notify();      	   		  
          } 	    	  
      }catch (InterruptedException ie) {ie.printStackTrace(); }
    }	  
  }

  public static void makeThread1True() {
    buffer_count = 0;
  }
        
  public static void makeThread2True() {
    buffer_count = 10;
  }
        
  public static void main(String[] args) throws IOException {
    makeThread1True();
    Runnable runnable1 = new MissedSignal(1);
    Thread t1 = new Thread(runnable1);
    t1.start();
  		  
    try {
  	  new Thread().sleep(5000);
	  makeThread2True();
    } catch (InterruptedException e) { e.printStackTrace(); }
  		   
    Runnable runnable2 = new MissedSignal(2);
    Thread t2 = new Thread(runnable2);
    t2.start();
  		  
    Runnable runnable3 = new MissedSignal(3);
    Thread t3 = new Thread(runnable3);
    t3.start();
  }
}

Compliant Solution

This compliant solution uses notifyAll() which sends notifications to all threads that wait on the same object. As a result, liveness is not affected unlike the noncompliant example. Ensure that the lock is released promptly after the call to notifyAll().

Code Block
bgColor#ccccff
else if(number == 3) {
  Thread.sleep(2000);	   		    			   
  list.notifyAll();      	   		  
} 	    	  

Risk Assessment

TODOTo guarantee the liveness of a system, the method notifyAll() should be called rather than notify().

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

CON02 CON32-J

?? low ??

unlikely

?? medium

P??

L??

Automated Detection

TODO

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

References

Wiki Markup
\[[Goetz 06|AA. Java References#Goetz 06]\] Section 
Concurrent,
14.2.4
. Notification
EJPLG, Item 50, Never invoke wait outside a loop
JLS, Chapter 17 Threads and
, Notification
\[[Bloch 01|AA. Java References#Bloch 01]\] Item 50: Never invoke wait outside a loop
\[[JLS 05|AA. Java References#JLS 05]\], Chapter 17, Threads and Locks