Java Threads Wait, Notify and NotifyAll Example

The purpose of using notify() and notifyAll() is to enable threads to communicate with one another via some object on which to performing the locking. A thread using the wait() method must own a lock on the object. Once wait() is called, the thread releases the lock, and waits for another thread to either call notify() or notifyAll() method. By using the wait() method, the thread is essentially saying that it is ready to process the additional request and is waiting for it to become available. Once it awakens after notify() or notifyAll() have been called, it will re-acquire the lock on the object and resume its normal execution.

The three methods: wait(), notify() and notifyAll() must be called inside of a synchronized block otherwise java.lang.IllegalMonitorStateException will be thrown.

These three methods: wait(), notify() and notifyAll() are found in the Object class.

wait()

The java.long.Object.wait method is an overloaded method that has three permutations. The first version, contains no parameters and will cause the thread to release ownership of the object’s lock (or monitor) and wait indefinitely until another thread calls either the notify or notifyAll methods. Another way to cause the thread to exit waiting is to have another thread call interrupt() which will cause a interruptedException on the thread.

The second version has a parameter milliseconds, specified as a long, so that the thread will wait until either notify or notifyAll gets called from another thread, is interrupted by another thread or the duration in milliseconds expires, called a spurious wakeup. Again, once the thread wakes up, it will need to re-acquire the object’s monitor before continuing execution.

Note

Please be aware that an illegalArgumentException will be thrown if the duration or timeout, which is specified as a long variable, is a negative value.

The last variation has a milliseconds parameter specified as a long, and an additional parameter for nanoseconds as an int variable. It is identical in all respects to the previous variation, except that it allows for finer grain control over the amount of time the thread will wait.

Wait Methods

MethodDescription
wait()Waits indefinitely until another thread calls either the notify or notifyAll methods or the thread is interrupted by another thread
wait(long millis)Waits at most milliseconds until either notify or notifyAll gets called from another thread, is interrupted by another thread or the duration in milliseconds expires, called a spurious wakeup
wait(long millis, int nanos)Waits at most milliseconds plus nanos until either notify or notifyAll gets called from another thread, is interrupted by another thread or the duration in milliseconds plus nanoseconds expires, called a spurious wakeup

notify()

The java.long.Object.notify() method wakes up a single thread waiting on the object’s monitor. If there are any threads waiting on the object’s monitor, one of them will arbitrarily chosen by the scheduler and woken up. Once awakened, the chosen thread will need to wait until the current thread relinquishes control of the object’s lock before proceeding.

notifyAll()

The java.long.Object.notifyAll() method wakes all the threads waiting on the object’s monitor. Once awakened, these threads will need to wait until the current thread relinquishes control of the object’s lock before proceeding. All the threads will get a chance to execute once each one has the released control on the object’s lock.

Broker / Runner Multithreaded Example using Runnable interface and Multiple Java Threads

In this Java Thread example, we have the Broker who typically works with clients to get Buy/Sell orders to purchase or sell certain stock symbols on behalf of the customer. A Runner is typically a broker employee who delivers market orders to the broker’s floor trader on the trading floor. After a customer places an order to the broker’s order taker, the runner will pass the instructions to the pit trader and wait for confirmation. Once the trade is executed, the runner will return to the order taker, confirming the order has been filled.

In my example, the Broker thread will loop ten times and create random sized orders between (1 ~ 10000) to Buy a random stock symbol on behalf of certain customer. Once it sets up the order by using the setOrder() method, it will send a signal to waiting threads by using the notify() method. The next available thread will then be awakened to acquire monitor on the Order Object and begin execution. Once it completes, the runner thread will go back into wait() state awaiting its next turn to run. Once all orders (10) have been sent, it will send out a broadcast announcement to all runners using the notifyAll() method.

The Runner thread’s job is to be ready to receive market orders from the Broker. It will go into a while loop while the isActive flag is true, and execute wait() method waiting for it to be notified by either the notify(), notifyAll() or via an interrupt() signal which will cause it to display that it was interrupted. If notified by one of the two methods available, it will attempt to acquire a lock on the Order class’ lock before processing order and displaying details about the received order.

WaitNotifyExample.java

package com.avaldes.tutorials;

public class WaitNotifyExample {
  private static Order order = new Order(); 

  public static void main(String[] args) {
    Thread[] t = new Thread[3];
    
    System.out.println("Starting all three runner threads..");
    for (int i = 0; i< 3; i++) {
      t[i] = new Thread(new Runner(order), "Runner_" + i);
      t[i].start();
    }
  
    // Main thread sleep for 2 seconds
    try {
      Thread.sleep(2000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    } 
    
    Thread broker = new Thread(new Broker(order), "Broker");
    broker.start();
    
    // Ensure main thread waits for broker thread to complete
    try {
      broker.join();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    
    // Make sure all runner threads are stopped...
    order.setActive(false);
    for (int i = 0; i< 3; i++) {
      t[i].interrupt();
    }
    
  }
}

Broker.java

package com.avaldes.tutorials;

import java.util.Random;

public class Broker implements Runnable {
  private Order order;
  private String symbols[] = new String[] {"AAPL", "ABT", "AXP", "BAC", "C", "COST", "CSCO", "EBAY", "FB", "FDX"};
  
  public Broker(Order order) {
    this.order = order;
  }
  
  public void run() {
    Random rand = new Random();
    
    System.out.println("Start of day, ready for new orders...");
    for (int i = 0; i<10; i++) {
      try {
        Thread.sleep(200);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      synchronized (order) {
        int orderSize = rand.nextInt(10000); if (orderSize==0) orderSize=100;
        int stockIdx = rand.nextInt(symbols.length); if (stockIdx > symbols.length) stockIdx=symbols.length;
        String details = String.format("Broker Order to Buy %d shares of %s", orderSize, symbols[stockIdx]);
        System.out.println("\n" + details);
        
        order.setOrder(details);
        order.notify();
      }
    }
    synchronized (order) {
      order.setOrder("ANNOUNCEMENT: End of Day");
      order.notifyAll();
    }
    System.out.println("End of day, completed all orders...");
  }
}

Runner.java

package com.avaldes.tutorials;

public class Runner implements Runnable {
  private Order order;
  
  public Runner(Order order) {
    this.order = order;
  }
  
  public void run() {
    while (order.isActive()) {
      System.out.format("%s is ready to receive order from Broker...\n", Thread.currentThread().getName());
      synchronized (order) {
        try {
          order.wait();
          System.out.format("%s received order, %s...\n", Thread.currentThread().getName(), order.getOrder());
        } catch (InterruptedException e) {
          System.out.format("%s was interrupted...\n", Thread.currentThread().getName());
        }
      }
    }
    System.out.format("%s Thread ending...\n", Thread.currentThread().getName());
  }
}

Order.java

package com.avaldes.tutorials;

public class Order {
  private String order;
  private volatile boolean  isActive;

  public boolean isActive() {
    return isActive;
  }

  public void setActive(boolean isActive) {
    this.isActive = isActive;
  }

  public Order() {
    this.isActive = true;
  }

  public String getOrder() {
    return order;
  }

  public void setOrder(String order) {
    this.order = order;
  }
}

Output

Starting all three runner threads..
Runner_0 is ready to receive order from Broker...
Runner_2 is ready to receive order from Broker...
Runner_1 is ready to receive order from Broker...
Start of day, ready for new orders...

Broker Order to Buy 5869 shares of EBAY
Runner_0 received order, Broker Order to Buy 5869 shares of EBAY...
Runner_0 is ready to receive order from Broker...

Broker Order to Buy 7643 shares of AAPL
Runner_2 received order, Broker Order to Buy 7643 shares of AAPL...
Runner_2 is ready to receive order from Broker...

Broker Order to Buy 1556 shares of C
Runner_1 received order, Broker Order to Buy 1556 shares of C...
Runner_1 is ready to receive order from Broker...

Broker Order to Buy 2640 shares of ABT
Runner_0 received order, Broker Order to Buy 2640 shares of ABT...
Runner_0 is ready to receive order from Broker...

Broker Order to Buy 775 shares of BAC
Runner_2 received order, Broker Order to Buy 775 shares of BAC...
Runner_2 is ready to receive order from Broker...

Broker Order to Buy 4380 shares of CSCO
Runner_1 received order, Broker Order to Buy 4380 shares of CSCO...
Runner_1 is ready to receive order from Broker...

Broker Order to Buy 9441 shares of AXP
Runner_0 received order, Broker Order to Buy 9441 shares of AXP...
Runner_0 is ready to receive order from Broker...

Broker Order to Buy 3947 shares of COST
Runner_2 received order, Broker Order to Buy 3947 shares of COST...
Runner_2 is ready to receive order from Broker...

Broker Order to Buy 9843 shares of BAC
Runner_1 received order, Broker Order to Buy 9843 shares of BAC...
Runner_1 is ready to receive order from Broker...

Broker Order to Buy 3035 shares of AXP
End of day, completed all orders...
Runner_0 received order, ANNOUNCEMENT: End of Day...
Runner_0 Thread ending...
Runner_1 received order, ANNOUNCEMENT: End of Day...
Runner_1 Thread ending...
Runner_2 received order, ANNOUNCEMENT: End of Day...
Runner_2 Thread ending...

Related Posts

  • Java Thread, Concurrency and Multithreading Tutorial
    This Java Thread tutorial will give you a basic overview on Java Threads and introduce the entire tutorial series on concurrency and multithreading. From here, you will learn about many java thread concepts like: Thread States, Thread Priority, Thread Join, and ThreadGroups. In addition, you will learn about using the volatile keyword and examples on using wait, notify and notifyAll.
  • Java Thread States - Life Cycle of Java Threads
    Get a basic understanding of the various thread states. Using the state transition diagram we show the various states for a Java thread and the events that cause the thread to jump from one state to another.
  • Creating Java Threads Example
    In this post we cover creating Java Threads using the two mechanisms provided in Java, that is, by extending the Thread class and by implementing Runnable interface for concurrent programming.
  • Java Thread Priority Example
    In this post we cover Thread priorities in Java. By default, a java thread inherits the priority (implicit) of its parent thread. Using the setPriority() method you can increase or decrease the thread priority of any java thread.
  • Java ThreadGroup Example
    Sometimes we will need to organize and group our threads into logical groupings to aid in thread management. By placing threads in a threadGroup all threads in that group can be assigned properties as a set, instead of going through the tedious task of assigning properties individually.
  • Java Thread Sleep Example
    We seem to use this method very often to temporarily suspend the current threads execution for a specific period of time. Let's spend some time and familiarize ourselves with what this method actually does.
  • Java Thread Join Example
    In Java, using Thread.join() causes the current thread to wait until the specified thread dies. Using this method allows us to impose an order such that we can make one thread wait until the other completes doing what it needed to do, such as completing a calculation.
  • Examining Volatile Keyword with Java Threads
    When we declare a field as volatile, the JVM will guarantee visibility, atomicity and ordering of the variable. Without it the data may be cached locally in CPU cache and as a result changes to the variable by another thread may not be seen by all other threads resulting in inconsistent behaviour.
  • Java Threads Wait, Notify and NotifyAll Example
    The purpose of using notify() and notifyAll() is to enable threads to communicate with one another via some object on which to performing the locking. A thread using the wait() method must own a lock on the object. Once wait() is called, the thread releases the lock, and waits for another thread to either call notify() or notifyAll() method.
  • Java Thread Deadlock Example and Thread Dump Analysis using VisualVM
    Deadlock is a condition where several threads are blocking forever, waiting for the other to finish but they never do. This tutorial will discuss situations that will lead to Java Thread deadlock conditions and how they can be avoided. In addition, we will discuss using Java VisualVM to pinpoint and analyze the source of the deadlock conditions.
  • Java Thread Starvation and Livelock with Examples
    Starvation occurs when a thread is continually denied access to resources and as a result it is unable to make progress. Thread liveLock is a condition that closely resembles deadlock in that several processes are blocking each other. But with livelock, a thread is unable to make any progress because every time it tries the operation always fails.
  • Java Synchronization and Thread Safety Tutorial with Examples
    One of Java's many strengths come from the fact that it supports multithreading by default as has so from the very onset. One of the mechanisms that Java uses for this is via synchronization. When we use the synchronized keyword in Java we are trying limit the number of threads that can simultaneously access and modify a shared resource. The mechanism that is used in Java's synchronization is called a monitor.
  • Creating a Thread Safe Singleton Class with Examples
    In this tutorial we cover many examples of creating thread-safe singleton classes and discuss some of the shortfalls of each and provide some recommendations on best approaches for a fast, efficient and highly concurrent solution.
  • Java Threads and Concurrent Locks with Examples
    In this tutorial we will focus primarily on using the concurrent utilities and how these can make concurrent programming easier for us.

Please Share Us on Social Media

Facebooktwitterredditpinterestlinkedinmail

Leave a Reply

Your email address will not be published. Required fields are marked *