Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Java Thread Waiting and Notification: wait, notify, and LockSupport

Tech May 14 1

notify():

Wakes up a single thread waiting on this object's monitor. The thread returns from wait only after it re-acquires the lock. If no lock is obtained, the thread goes back to the WAITING state.

notifyAll():

Wakes up all threads waiting on this object's monitor.

wait():

Causes the current thread to enter the WAITING state until another thread notifies it or it is interrupted. Note that calling wait() releases the object’s lock.

wait(long timeout):

Waits for at most timeout milliseconds. Returns if not notified before the timeout.

Standard usage pattern

Waiting side
synchronized(monitor) {
   while(condition not met) {
       monitor.wait();
   }
}
Notifying side
synchronized(monitor) {
   // change the condition
   monitor.notify();
}
Why synchronization is required

Assume party A is the waiter and party B is the notifier. If A checks the condition (finds it false) and then loses the CPU before calling wait, by that time B may have already changed the condition and called notify. When A resumes, it calls wait and may wait forever. Synchronization prevents this gap.

Example: Weighbridge System

Three steps are involved:

  1. Vehicle license plate recognition (cannot weigh because the driver hasn't left the vehicle yet).
  2. Capture vehicle photo (cannot capture because the driver hasn't left the vehicle yet).
  3. The driver gets out and swipes a card at the reader, wich wakes up the tasks in steps 1 and 2.
public class WeighbridgeDemo {
   static boolean driverCardSwiped = false;

   public static void main(String[] args) {
       Object monitor = new Object();

       // Weighing thread
       new Thread(() -> {
           System.out.println("[Weighbridge] Camera recognized vehicle, waiting for driver to swipe card...");
           while (!driverCardSwiped) {
               synchronized (monitor) {
                   try {
                       monitor.wait();
                   } catch (InterruptedException e) {
                       throw new RuntimeException(e);
                   }
               }
           }
           System.out.println("[Weighbridge] Card swiped, starting weighing...");
       }).start();

       // Photo capture thread
       new Thread(() -> {
           System.out.println("[Weighbridge] Capturing photo...");
           while (!driverCardSwiped) {
               synchronized (monitor) {
                   try {
                       monitor.wait();
                   } catch (InterruptedException e) {
                       throw new RuntimeException(e);
                   }
               }
           }
           System.out.println("[Weighbridge] Photo capture completed.");
       }).start();

       // Card‑swipe thread
       new Thread(() -> {
           try {
               Thread.sleep(3000);
               synchronized (monitor) {
                   driverCardSwiped = true;
                   monitor.notifyAll();
               }
           } catch (InterruptedException e) {
               throw new RuntimeException(e);
           }
       }).start();
   }
}

Should we use notify or notifyAll?

Prefer notifyAll() whenever possible. Use notify() with caution because it only wakes one thread, and you cannot guarantee that the woken thread is the one you actually need to proceed.

When do wait and notify release the lock?

wait: releases the lock immediately upon invocation. When it is woken up it will re‑compete for the lock, and only after re‑acquiring it will continue execution after wait().

notify: the lock is released only when the enclosing synchronized block fully completes. Notify usually appears at the end of the block because you want to first finish all condition modifications before alerting other threads.

(2) Waking up a specific thread

The notify family of methods cannot wake a specific thread. To wake a designated thread you can use LockSupport:

public class LockSupportDemo {
   public static void main(String[] args) {
       Thread worker1 = new Thread(() -> {
           LockSupport.park();
           System.out.println("Worker-1 running");
       });
       Thread worker2 = new Thread(() -> {
           LockSupport.park();
           System.out.println("Worker-2 running");
       });

       worker1.start();
       worker2.start();

       LockSupport.unpark(worker1);
   }
}

When park() is executed it first checks for a permit. With out a permit the thread blocks.

unpark(thread) issues a permit, waking the specified thread if it was blocked due to lack of a permit.

Note: park and unpark have no ordering requirement. If unpark is called first, a subsequetn park will return immediately.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.