Daniel.Schroeder Daniel.Schroeder - 7 months ago 6
Java Question

Trying to Get Guarded Blocks to Work

I'm not understanding why my code is not working correctly. I expect the first Thread to wait for 4 seconds for the second Thread to set a shared boolean "joy" to true, then for the first Thread to print out "Joy has been achieved!".

When I run the code, I get this output:


"No Joy Yet..."

"Notifying Joy"


Then it freezes up and doesn't continue. If my understanding is correct, the notifyAll() method which is called from my notifyJoy() method should wake t1 up from its wait() and then, since the shared static boolean variable joy is now true, "Joy has been achieved!" should print to the console.

I'm working from Oracle's "The Java Tutorial", Chapter 13: here is a link to the specific section: Java Tutorial Website. I'm going off of what they have and making a little example but I can't seem to figure out what I'm doing wrong. Any help would be appreciated. Here is a complete copy of my code for your reference:

public class JoyTime {

public static void main(String[] args) {
JoyRider j1 = new JoyRider(false);
JoyRider j2 = new JoyRider(true);

Thread t1 = new Thread(j1, "J1");
Thread t2 = new Thread(j2, "J2");

t1.start();

try {
Thread.sleep(4000);
}
catch (InterruptedException e) {}

t2.start();
}
}

class JoyRider implements Runnable {

private static boolean joy = false;
private boolean flag;

public JoyRider(boolean flag) {
this.flag = flag;
}

@Override
public void run() {
synchronized(this) {
if (flag) {
notifyJoy();
}
else {
while (!joy) {
System.out.println("No Joy Yet...");
try {
this.wait();
}
catch (InterruptedException e) {}
}
System.out.println("Joy has been achieved!");
}
}
}

public synchronized void notifyJoy() {
System.out.println("Notifying Joy");
joy = true;
notifyAll();
}
}

Answer

You are calling wait() and notifyAll() on different monitors, and more specifically on the built-in monitors of the two different JoyRider instances.

If you introduce a dedicated lock object:

private static final Object LOCK = new Object();

and change your run() method a little:

synchronized (LOCK) {
   if (flag) {
      System.out.println("Notifying Joy");
      JOY = true;
      LOCK.notifyAll();
   }
   else {
      while (!JOY) {
         System.out.println("No Joy Yet...");
         try {
            LOCK.wait();
         }
         catch (InterruptedException e) {}
      }
      System.out.println("Joy has been achieved!");
   }
}

you should be able to see all the expected prints in the correct order.