A quick analysis of the code is:
- Thread 1 and Thread 2 start. They both use a Runnable object which initialize the wait flag to true.
- The start method calls the run methods which sleeps for a while, then switch the wait flag to false and notify any possible blocking threads.
- In the mean time, the main thread calls the get method which wait to be notified, then check if the wait flag is true.
Should be straightforward? but the program actually blocks.
Taking a closer look, here is what is going on:
The moral of this story is that as everyone knows it is way too easy to make this sort of
mistakes. To make concurrent programming little bit easier, Java 1.5 introduced the
java.util.concurrent package and several classes to ease the development of multi-threads
applications. Looking back at our problem, we want to ensure the run method is executed first,
then the get method. A possible solution (I just started learning about these new classes!)
is to use the new CountDownLatch class:
- A CountDownLatch is initialized with a given count. The await methods block until the current count reaches zero due to invocations of
the countDown() method.
Also, since we are not using the wait and notifyAll calls directly any longer it is not necessary
to synchronized the run and get methods. The implementation of the class becomes:
class CRun1 implements Runnable {
String s;
CountDownLatch c = new CountDownLatch(1);
CRun1(String s) {
this.s = s;
}
public void run() {
System.out.println("Lrun " + s);
try {
Thread.sleep(4000);
} catch (InterruptedException ex) {
} finally {
}
System.out.println("count down - notify for run " + s);
c.countDown();
}
public void get() {
while (true) {
try {
c.await();
break;
} catch (InterruptedException ex) {
}
}
System.out.println("recv notify...");
}
}