This example shows a Java™ program using condition variables in the form of the wait and notify methods on a Java object. Note the locking protocol used.
/* FileName: ATEST18.java The output of this example is as follows: Entered the testcase Create/start the thread Consumer Thread-1: Entered Consumer Thread-1: Wait for the data to be produced Producer: 'Finding data Consumer Thread-2: Entered Consumer Thread-2: Wait for the data to be produced Producer: Make data shared and notify consumer Producer: Unlock shared data and flag Consumer Thread-2: Found data or notified, CONSUME IT while holding inside the monitor Consumer Thread-2: Wait for the data to be produced Producer: 'Finding data Producer: Make data shared and notify consumer Producer: Unlock shared data and flag Producer: 'Finding data Consumer Thread-2: Found data or notified, CONSUME IT while holding inside the monitor Consumer Thread-2: All done Producer: Make data shared and notify consumer Producer: Unlock shared data and flag Producer: 'Finding data Consumer Thread-1: Found data or notified, CONSUME IT while holding inside the monitor Consumer Thread-1: Wait for the data to be produced Producer: Make data shared and notify consumer Producer: Unlock shared data and flag Wait for the threads to complete Consumer Thread-1: Found data or notified, CONSUME IT while holding inside the monitor Consumer Thread-1: All done Testcase completed */ import java.lang.*; /* This class is an encapsulation of the condition variable plus */ /* mutex locking logic that can be seen in the Pthread example */ class theSharedData extends Object { int dataPresent; int sharedData; public theSharedData() { dataPresent=0; sharedData=0; } public synchronized void get() { while (dataPresent == 0) { try { System.out.print("Consumer " + Thread.currentThread().getName() + ": Wait for the data to be produced\n"); wait(); } catch (InterruptedException e) { System.out.print("Consumer " + Thread.currentThread().getName() + ": wait interrupted\n"); } } System.out.print("Consumer " + Thread.currentThread().getName() + ": Found data or notified, CONSUME IT " + "while holding inside the monitor\n"); --sharedData; if (sharedData == 0) {dataPresent=0;} /* in a real world application, the actual data would be returned */ /* here */ } public synchronized void put() { System.out.print("Producer: Make data shared and notify consumer\n"); ++sharedData; dataPresent=1; notify(); System.out.print("Producer: Unlock shared data and flag\n"); /* unlock occurs when leaving the synchronized method */ } } public class ATEST18 { public final static int NUMTHREADS = 2; public static theSharedData dataConditionEncapsulation = new theSharedData(); static class theThread extends Thread { public void run() { int retries=2; System.out.print("Consumer " + getName() + ": Entered\n"); while (retries-- != 0) { dataConditionEncapsulation.get(); /* Typically an application would process the data outside */ /* the monitor (synchronized get method here) */ } System.out.print("Consumer " + getName() + ": All done\n"); } } public static void main(String argv[]) { int amountOfData = 4; theThread threads[] = new theThread[NUMTHREADS]; System.out.print("Entered the testcase\n"); System.out.print("Create/start the thread\n"); for (int i=0; i <NUMTHREADS; ++i) { threads[i] = new theThread(); threads[i].start(); } while (amountOfData-- != 0) { System.out.print("Producer: 'Finding data\n"); try { Thread.sleep(3000); } catch (InterruptedException e) { System.out.print("sleep interrupted\n"); } dataConditionEncapsulation.put(); } System.out.print("Wait for the threads to complete\n"); for(int i=0; i <NUMTHREADS; ++i) { try { threads[i].join(); } catch (InterruptedException e) { System.out.print("Join interrupted\n"); } } System.out.print("Testcase completed\n"); System.exit(0); } }