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()
andnotifyAll()
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;
}
public void printEven() throws InterruptedException {
synchronized (this) {
for (int i = 0; i < max; i++) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + "-" + i);
notify();
} else {
wait();
}
}
}
}
public void printOdd() throws InterruptedException {
synchronized (this) {
for (int i = 0; i < max; i++) {
if (i % 2 == 0) {
wait();
} else {
System.out.println(Thread.currentThread().getName() + "-" + i);
notify();
}
}
}
}
}
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