Adverts
Threads are built right into the very heart of Java and one of the best ways of managing threads is with the wait and notifty mechanism. The example below shows a some what contrived use of wait and notify. The main thread creates a worker thread and then waits to be notified that it is time to exit. This application generally works but it has a fatal flaw in that it can miss the notification.
public class WaitAndNotify1 {
public WaitAndNotify1() {
System.out.println( "Starting worker thread." );
Worker worker = new Worker();
worker.start();
System.out.println( "Worker thread started." );
//Wait has to be called inside a synchronized
//block so that we own the monitor.
synchronized (this) {
//We need a boolean to check to see whether we are actually really shutting
//down or whether we have been woken by mistake.
try {
System.out.println( "Waiting for worker thread..." );
wait();
System.out.println( "Got a notification or interrupt. Probably time to shutdown." );
} catch (InterruptedException e) {
//If we have received an interrupt it's time to shutdown.
Thread.currentThread().isInterrupted();
}
System.out.println( "Shutting down main thread." );
}
}
public static void main( String[] args ) {
new WaitAndNotify1();
}
private class Worker extends Thread {
public void run() {
System.out.println( "I'm working really hard!" );
//This little seen piece of syntax is used by non-static inner class that
//wants to get the implicit reference to their enclosing object.
synchronized (WaitAndNotify1.this) {
WaitAndNotify1.this.notify();
}
}
}
}
The execution trace of this application makes it seem that the application works fine:
Starting worker thread. Worker thread started. Waiting for worker thread... I'm working really hard! Got a notification or interrupt. Probably time to shutdown. Shutting down main thread.
The problem is that if the worker thread issues its notify before the main thread executes the call to wait the main thread will miss the notification and never return from the wait. This would, of course, be a very bad thing to hava happen as there would then be no way for the application to proceed. The situation can be simulated by including a one second sleep in the main thread just after it spawns the worker thread. In theory no delay is complete guaranteed to be long enough, in practice one second is ample.
public class WaitAndNotify2 {
public WaitAndNotify2() {
System.out.println( "Starting worker thread." );
Worker worker = new Worker();
worker.start();
System.out.println( "Worker thread started." );
try {
Thread.currentThread().sleep( 1000 );
} catch (InterruptedException sleepException ) {
sleepException.printStackTrace();
}
//Wait has to be called inside a synchronized
//block so that we own the monitor.
synchronized (this) {
//We need a boolean to check to see whether we are actually really shutting
//down or whether we have been woken by mistake.
try {
System.out.println( "Waiting for worker thread..." );
wait();
System.out.println( "Got a notification or interrupt. Probably time to shutdown." );
} catch (InterruptedException e) {
//If we have received an interrupt it's time to shutdown.
Thread.currentThread().isInterrupted();
}
}
System.out.println( "Shutting down main thread." );
}
public static void main( String[] args ) {
new WaitAndNotify2();
}
private class Worker extends Thread {
public void run() {
System.out.println( "I'm working really hard!" );
//This little seen piece of syntax is used by non-static inner class that
//wants to get the implicit reference to their enclosing object.
synchronized (WaitAndNotify2.this) {
WaitAndNotify2.this.notify();
}
}
}
}
As can bee see from this application trace it never exits:
Starting worker thread. Worker thread started. I'm working really hard! Waiting for worker thread...
A solution to this problem is to use a flag indicating that the worker has requested a shutdown. The main thread then checks this flag before waiting. If the main thread is delayed for some reason and the worker requests a shutdown before the main thread has ever waited the main thread will simply never wait. The flag must be volatile to ensure that the main thread sees the most up to date version.
public class WaitAndNotify3 {
private volatile boolean shutdown = false;
public WaitAndNotify3() {
System.out.println( "Starting worker thread." );
Worker worker = new Worker();
worker.start();
System.out.println( "Worker thread started." );
try {
Thread.currentThread().sleep( 1000 );
} catch (InterruptedException sleepException ) {
sleepException.printStackTrace();
}
//Wait has to be called inside a synchronized
//block so that we own the monitor.
synchronized (this) {
//We need a boolean to check to see whether we are actually really shutting
//down or whether we have been woken by mistake.
if( !shutdown ) {
try {
System.out.println( "Waiting for worker thread..." );
wait();
System.out.println( "Got a notification or interrupt. Probably time to shutdown." );
} catch (InterruptedException e) {
//If we have received an interrupt it's time to shutdown.
Thread.currentThread().isInterrupted();
shutdown = true;
}
}
System.out.println( "Shutting down main thread." );
}
}
public static void main( String[] args ) {
new WaitAndNotify3();
}
private class Worker extends Thread {
public void run() {
System.out.println( "I'm working really hard!" );
//This little seen piece of syntax is used by non-static inner class that
//wants to get the implicit reference to their enclosing object.
synchronized (WaitAndNotify3.this) {
shutdown = true;
WaitAndNotify3.this.notify();
}
}
}
}
The execution trace for this application is:
Starting worker thread. Worker thread started. I'm working really hard! Shutting down main thread.
As you can see the main thread never even tries to wait. This system and be extended to any number of threads with ease. Checking to see whether the conditions of a wait are valid before entering a wait and after exiting must always be carried out to ensure the wait is valid. Failue to do so can easily result in a program that breaks for no apparent reason.