Using wait/notify vs Thread.sleep() in Java

Using wait/notify vs Thread.sleep() in Java

Last Updated: June 1, 20232.1 min readCategories: Technical & Development
Jump to Section:
Share Post

Using wait/notify vs Thread.sleep() in Java

This is a pattern I see very often when doing Java code reviews. There is one thread that is doing some processing on some type of object or file, then another thread needs to act on that object or file when it is finished.
Often times developers will take the simple approach and just make the waiting thread call Thread.sleep in a while loop, sleeping the thread while waiting for the other thread to finish. This method is shown in the example below.

public class TestProcessesSleep {
  private static boolean fileProcessed = false;
  
  public static class Process1Thread extends Thread
  {
    public void run() {
      while(!fileProcessed) {
        try {
          Thread.sleep(1000);
        } catch(InterruptedException e) {
          
        }
      }
      
      System.out.println("File Processed, now upload file...");
    }
  }
  
  public static class Process2Thread extends Thread
  {
    public void run() {
      System.out.println("Start Processing File...");
      
      //do some processing on the files here...
      
      fileProcessed = true;
    }
  }
  
  public static void main(String[] args) {
    new Process1Thread().start();
    new Process2Thread().start();
  }
}

Using Thread.sleep in a loop is sort of the lazy way of doing thread synchronization, you also need to make sure that you pick a parameter that’s large enough that it doesn’t cost you a lot of CPU cycles doing the boolean check but also small enough that you don’t waste a lot of time that could be spent processing the next step when the other thread is complete.
The proper way to do this sort of thread synchronization is to make use of the wait and notifyAll methods as shown in the example below.

public class TestProcessesWait {
  private static Object monitor = new Object();
  private static boolean fileProcessed = false;
  
  public static class Process1Thread extends Thread
  {
    public void run() {
      while(!fileProcessed) {
        synchronized(monitor) {
          try {
            monitor.wait();
          } catch(InterruptedException e) {
          
          }
        }
      }
      
      System.out.println("File Processed, now upload file...");
    }
  }
  
  public static class Process2Thread extends Thread
  {
    public void run() {
      System.out.println("Start Processing File...");
      
      //do some processing on the files here...
      
      fileProcessed = true;
      
      synchronized(monitor) {
        monitor.notifyAll();
      }
    }
  }
  
  public static void main(String[] args) {
    new Process1Thread().start();
    new Process2Thread().start();
  }
}

Notice that in this example, we have an object that is shared between the two threads, this is a “monitor” object that we will be synchronizing the threads on.

private static Object monitor = new Object();

Now in the waiting thread, we replace the call to Thread.sleep() with a call to monitor.wait(), and this needs to be within a synchronized(monitor) block. The wait call still needs to catch InterruptedException because the wait can also be interrupted. Also, you technically don’t need to put this wait() call within a while(!fileProcessed) block, at least not in this example, but to be safe you should always keep this check in place in case any other thread cases the thread to be notified or if the wait gets interrupted by some other thread.

synchronized(monitor) {
  try {
    monitor.wait();
  } catch(InterruptedException e) {
    
  }
}

Finally, when the processing thread is finished processing the object or file it’s working on, a call to monitor.notifyAll() is called to wake up the other thread.

synchronized(monitor) {
  monitor.notifyAll();
}

This might be a little bit more code and maybe a little bit more complicated than simply sleeping and looping but this is the proper way to do thread synchronization in Java and it makes use of the operating system’s scheduler instead of sleeping for arbitrary amounts of time. Calling wait() will tell the OS that you are done with your processing and don’t need any CPU cycles until someone wakes you up with a call to notifyAll().

Stay in the loop

Subscribe to Our Newsletter and Get the Latest From the QAT Global