...
These are typically true when only one thread is waiting. Otherwise, if either doesn't condition does not hold, incorrect program behavior may result.
...
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 are used. One checks whether the buffer has zero elements and another that the other 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 becomes 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 its condition turns out to be false
. Even though this notify was notification is meant for thread 2 (whose condition is on the other hand, true
) thread 1 wakes up on its false
condition.
Code Block | ||
---|---|---|
| ||
import java.util.LinkedList; import java.io.IOException; 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(); } } |
...
EX1: If there are several similar threads waiting for a notification, and it is permissible to invoke either of them, notify()
may be used. There should be a relaxed liveness criteriaThe criteria for liveness is relaxed in this case.
Risk Assessment
To guarantee the liveness of a system, the method notifyAll()
should must be called rather instead of than notify()
.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
CON32- J | low | unlikely | medium | P2 | L3 |
...