Java Object wait() Method

There are three overloaded Object.wait() methods in Java are used to pause the execution of the current thread until it is awakened, typically by being notified or interrupted.

Table of Contents

  1. Introduction
  2. wait() Method Syntax
    • final void wait()
    • final void wait(long timeoutMillis)
    • final void wait(long timeoutMillis, int nanos)
  3. Examples
    • Basic Waiting and Notification
    • Waiting with Timeout
  4. Real-World Use Case
  5. Conclusion

Introduction

The Object.wait() methods are members of the Object class in Java. These methods cause the current thread to wait until another thread invokes the notify() or notifyAll() methods for this object, or some other thread interrupts the current thread, or a specified amount of time has elapsed.

wait()() Method Syntax

Here are the three overloaded methods:

final void wait()

The syntax for the wait() method without parameters is as follows:

public final void wait() throws InterruptedException

This method causes the current thread to wait indefinitely until it is notified or interrupted.

final void wait(long timeoutMillis)

The syntax for the wait() method with a timeout in milliseconds is as follows:

public final void wait(long timeoutMillis) throws InterruptedException

This method causes the current thread to wait until it is notified, interrupted, or the specified timeout elapses.

final void wait(long timeoutMillis, int nanos)

The syntax for the wait() method with a timeout in milliseconds and nanoseconds is as follows:

public final void wait(long timeoutMillis, int nanos) throws InterruptedException

This method causes the current thread to wait until it is notified, interrupted, or the specified timeout elapses.

Examples

Basic Waiting and Notification

To use the wait() method, a thread must acquire the object's monitor by synchronizing on it. The notify() method is used to wake up a waiting thread.

Example

class WaitNotifyExample {
    private final Object lock = new Object();

    public void waitingMethod() {
        synchronized (lock) {
            try {
                System.out.println("Waiting thread is going to wait...");
                lock.wait();
                System.out.println("Waiting thread is resumed.");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void notifyingMethod() {
        synchronized (lock) {
            System.out.println("Notifying thread is going to notify...");
            lock.notify();
            System.out.println("Notifying thread has called notify.");
        }
    }

    public static void main(String[] args) {
        WaitNotifyExample example = new WaitNotifyExample();

        Thread waitingThread = new Thread(example::waitingMethod);
        Thread notifyingThread = new Thread(example::notifyingMethod);

        waitingThread.start();

        try {
            // Ensure the waiting thread starts waiting before the notifying thread calls notify
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        notifyingThread.start();
    }
}

Output:

Waiting thread is going to wait...
Notifying thread is going to notify...
Notifying thread has called notify.
Waiting thread is resumed.

Waiting with Timeout

The wait(long timeoutMillis) method can be used to wait with a specified timeout.

Example

class WaitTimeoutExample {
    private final Object lock = new Object();

    public void waitingMethod() {
        synchronized (lock) {
            try {
                System.out.println("Waiting thread is going to wait for 2 seconds...");
                lock.wait(2000);
                System.out.println("Waiting thread is resumed or timed out.");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void notifyingMethod() {
        synchronized (lock) {
            try {
                Thread.sleep(1000); // Simulate some work
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Notifying thread is going to notify...");
            lock.notify();
            System.out.println("Notifying thread has called notify.");
        }
    }

    public static void main(String[] args) {
        WaitTimeoutExample example = new WaitTimeoutExample();

        Thread waitingThread = new Thread(example::waitingMethod);
        Thread notifyingThread = new Thread(example::notifyingMethod);

        waitingThread.start();
        notifyingThread.start();
    }
}

Output:

Waiting thread is going to wait for 2 seconds...
Notifying thread is going to notify...
Notifying thread has called notify.
Waiting thread is resumed or timed out.

Real-World Use Case

Producer-Consumer Problem with Timeout

In a real-world scenario, the wait(long timeoutMillis) method can be used to solve the producer-consumer problem where producers put items into a shared resource and consumers take items out. The wait() method can be used to make consumers wait for items and producers wait for space to be available, with a timeout to prevent indefinite waiting.

Example

import java.util.LinkedList;
import java.util.Queue;

class ProducerConsumerTimeoutExample {
    private final Queue<Integer> queue = new LinkedList<>();
    private final int MAX_SIZE = 5;
    private final Object lock = new Object();

    public void produce() throws InterruptedException {
        int value = 0;
        while (true) {
            synchronized (lock) {
                while (queue.size() == MAX_SIZE) {
                    System.out.println("Queue is full. Producer is waiting...");
                    lock.wait();
                }
                queue.offer(value);
                System.out.println("Produced: " + value);
                value++;
                lock.notify();
            }
            Thread.sleep(1000); // Simulate time taken to produce an item
        }
    }

    public void consume() throws InterruptedException {
        while (true) {
            synchronized (lock) {
                while (queue.isEmpty()) {
                    System.out.println("Queue is empty. Consumer is waiting...");
                    lock.wait(2000);
                    System.out.println("Consumer waited for 2 seconds or was notified.");
                }
                int value = queue.poll();
                System.out.println("Consumed: " + value);
                lock.notify();
            }
            Thread.sleep(1000); // Simulate time taken to consume an item
        }
    }

    public static void main(String[] args) {
        ProducerConsumerTimeoutExample example = new ProducerConsumerTimeoutExample();

        Thread producerThread = new Thread(() -> {
            try {
                example.produce();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread consumerThread = new Thread(() -> {
            try {
                example.consume();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        producerThread.start();
        consumerThread.start();
    }
}

Output:

Produced: 0
Consumed: 0
Produced: 1
Consumed: 1
Queue is empty. Consumer is waiting...
Consumer waited for 2 seconds or was notified.
Produced: 2
...

Conclusion

These three overloaded Object.wait() methods in Java provide a powerful mechanism for thread communication and synchronization. By understanding how to use these methods, you can effectively coordinate activities between multiple threads. Whether you are using the basic wait() method, the wait(long timeoutMillis) method with a timeout, or solving complex scenarios like the producer-consumer problem, the wait() methods offer a reliable way to manage thread interactions in Java applications.

Comments