Learnitweb

Printing Even and Odd Numbers Using Two Synchronized Threads in Java

1. Problem Description

We want:

  • Thread 1 (OddThread) → prints odd numbers: 1, 3, 5, 7, …
  • Thread 2 (EvenThread) → prints even numbers: 2, 4, 6, 8, …

Both should print numbers in sequence, i.e.,
1 2 3 4 5 6 7 8 ... (not random interleaving).

To achieve this, we’ll make the two threads communicate and coordinate using wait() and notify() on a shared object lock.

2. Core Idea

  • Both threads share a common lock object and a shared counter variable.
  • Each thread checks whether it’s its turn (odd or even).
  • If it’s not its turn, it calls wait().
  • After printing, it increments the counter and calls notify() to wake the other thread.

3. Step-by-Step Logic

  1. Initialize a shared variable number = 1.
  2. Define a limit, say MAX = 10.
  3. Create one thread for odd numbers and one for even numbers.
  4. Use a common lock object:
    • When the odd thread runs:
      • It prints only if number % 2 != 0.
      • After printing, it increments and notifies the even thread.
    • When the even thread runs:
      • It prints only if number % 2 == 0.
      • After printing, it increments and notifies the odd thread.

This ensures alternating execution.

4. Complete Java Program

public class EvenOddThreadSync {

    private int number = 1; // Shared counter
    private final int MAX = 10; // Upper limit
    private final Object lock = new Object(); // Common lock object

    public static void main(String[] args) {
        EvenOddThreadSync printer = new EvenOddThreadSync();
        Thread oddThread = new Thread(() -> printer.printOdd());
        Thread evenThread = new Thread(() -> printer.printEven());

        oddThread.start();
        evenThread.start();
    }

    // Method for odd numbers
    public void printOdd() {
        synchronized (lock) {
            while (number <= MAX) {
                while (number % 2 == 0) { // Wait if it's even's turn
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
                if (number <= MAX) {
                    System.out.println("Odd Thread: " + number);
                    number++;
                    lock.notify(); // Wake up even thread
                }
            }
        }
    }

    // Method for even numbers
    public void printEven() {
        synchronized (lock) {
            while (number <= MAX) {
                while (number % 2 != 0) { // Wait if it's odd's turn
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
                if (number <= MAX) {
                    System.out.println("Even Thread: " + number);
                    number++;
                    lock.notify(); // Wake up odd thread
                }
            }
        }
    }
}

5. Sample Output

Odd Thread: 1
Even Thread: 2
Odd Thread: 3
Even Thread: 4
Odd Thread: 5
Even Thread: 6
Odd Thread: 7
Even Thread: 8
Odd Thread: 9
Even Thread: 10

6. How It Works Internally

  1. Both threads start and compete for the lock.
  2. Initially, number = 1, so printOdd() executes.
  3. The odd thread prints 1, increments the counter to 2, and calls notify().
  4. The even thread wakes up, prints 2, increments the counter to 3, and calls notify().
  5. This alternating pattern continues until the limit is reached.

The wait() and notify() methods ensure that:

  • Only one thread prints at a time.
  • Threads alternate execution in perfect sync.

7. Alternative: Using Lock and Condition (Modern Approach)

A cleaner way using Java’s ReentrantLock and Condition:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class EvenOddLockExample {

    private int number = 1;
    private final int MAX = 10;
    private final Lock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();

    public static void main(String[] args) {
        EvenOddLockExample printer = new EvenOddLockExample();
        Thread oddThread = new Thread(printer::printOdd);
        Thread evenThread = new Thread(printer::printEven);

        oddThread.start();
        evenThread.start();
    }

    public void printOdd() {
        while (number <= MAX) {
            lock.lock();
            try {
                while (number % 2 == 0) {
                    condition.await();
                }
                if (number <= MAX) {
                    System.out.println("Odd Thread: " + number);
                    number++;
                    condition.signalAll();
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                lock.unlock();
            }
        }
    }

    public void printEven() {
        while (number <= MAX) {
            lock.lock();
            try {
                while (number % 2 != 0) {
                    condition.await();
                }
                if (number <= MAX) {
                    System.out.println("Even Thread: " + number);
                    number++;
                    condition.signalAll();
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                lock.unlock();
            }
        }
    }
}

This approach avoids intrinsic locks (synchronized) and gives finer control over thread signaling.

8. Key Takeaways

ConceptExplanation
Shared objectEnsures both threads coordinate using a single lock
wait()Causes the thread to pause and release the lock
notify()Wakes up one waiting thread on the same lock
SynchronizationEnsures visibility and mutual exclusion
ReentrantLockModern alternative to synchronized with explicit control
ConditionProvides finer signaling control (similar to wait/notify)