Java Program to Print Odd/Even Numbers using 2 Threads

Printing odd and even numbers in sequence using 2 threads is a use case of synchronization and inter thread communication.

Table of Contents

Printing odd and even numbers in sequence using 2 threads is a use case of synchronization and inter thread communication.

Problem Statement

We have to print odd and even numbers in sequence using 2 threads, that means one thread is printing only odd numbers and another one is printing even numbers only.

Solution

Let’s say we have a common resource called Printer and 2 threads called OddPrinter and EvenPrinter are trying to access it. In order to make them print in sequence, we need to use below 2 concepts.

  • Resource synchronization: Whenever multiple threads are accessing a common resource, we need to synchronize that resource so that it can be accessed by 1 thread at a time and data discrepancy can be avoided.
  • Inter thread communication: Whenever we need communication between threads, we use this concept. In our example, to make them print in sequence, we need to make both the printers/threads communicate with each other. We achieve this by using wait(), notify() and notifyAll() methods in Java.

Implementation

To implement the solution, we need to break it down into 4 pieces which are the following.

  • CommonPrinter
  • OddPrinter
  • EvenPrinter
  • Main class to run the code

CommonPrinter

This class contains logic. The Printer object is the resource that gets accessed by both the threads hence it is synchronized.

It offers 2 methods i.e. printEven() and printOdd() that get called by EvenPrinter and OddPrinter threads respectively.

public class Printer {
    private final int max;

    public Printer(int max) {
        this.max = max;
    }

    /**
     * This method gets called from EvenPrinter and it only prints Even values.
     *
     * @throws InterruptedException
     */
    public void printEven() throws InterruptedException {
        synchronized (this) {   //Since this is a common resource, it needs to be synchronized.
            for (int i = 0; i < max; i++) {
                if (i % 2 == 0) {
                    System.out.println(Thread.currentThread().getName() + "-" + i);  //Even values can be printed directly since it is an EvenPrinter, no magic here.
                    notify();   //Notify the another thread (OddPrinter) so that that can continue.
                } else {
                    wait(); //Since it is an EvenPrinter, it needs to wait at odd values.
                }
            }
        }
    }

    /**
     * This method gets called from OddPrinter and it prints only Odd values.
     *
     * @throws InterruptedException
     */
    public void printOdd() throws InterruptedException {
        synchronized (this) {
            for (int i = 0; i < max; i++) {
                if (i % 2 == 0) {
                    wait();     //Waiting at even values since it is an OddPrinter.
                } else {
                    System.out.println(Thread.currentThread().getName() + "-" + i);  //Printing odd values directly since it is an Odd printer, no magic here.
                    notify();   //Notify the EvenPrinter so that that can continue.
                }
            }
        }
    }
}

OddPrinter

OddPrinter is a Runnable task that gets executed via a Thread. We can also make OddPrinter a thread by extending the Thread class but for simplicity we have made it a Runnable task.

It internally calls the printOdd() of the Printer class.

public class OddPrinter implements Runnable {
    private final Printer printer;

    public OddPrinter(Printer printer) {
        this.printer = printer;
    }

    @Override
    public void run() {
        try {
            printer.printOdd();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

EvenPrinter

EvenPrinter is also a Runnable task that gets run by a Thread. It calls the printEven() of the Printer class to print even numbers.

public class EvenPrinter implements Runnable {
    private final Printer printer;

    public EvenPrinter(Printer printer) {
        this.printer = printer;
    }

    @Override
    public void run() {
        try {
            printer.printEven();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Main Class

In the main class we create an object of the Printer class which is going to be used by OddPrinter and EvenPrinter

The Printer class takes a parameter called max that takes a number till what you want to print the numbers.

public class Main {
    public static void main(String[] args) {
        Printer printer = new Printer(10);
        Thread odd = new Thread(new OddPrinter(printer));   //Common printer to be used by OddPrinter
        odd.setName("ODD");
        Thread even = new Thread(new EvenPrinter(printer)); //Common printer to be used by EvenPrinter
        even.setName("EVEN");
        odd.start();
        even.start();
    }
}

Output

EVEN-0
ODD-1
EVEN-2
ODD-3
EVEN-4
ODD-5
EVEN-6
ODD-7
EVEN-8
ODD-9