Search code examples
javamultithreadingconcurrencythread-safetyrunnable

print odd and even numbers using two threads in java efficiently?


I was asked below question in an interview where I need to print out even and odd numbers using two threads so I came up with below code but in this I am using two classes one which implements runnable interface and other to print out the number which uses wait and notifyAll.

public class PrintEvenOddTester {

  public static void main(String[] args) {
    Output print = new Output();
    Thread t1 = new Thread(new EvenOddTask(print, 10, false));
    Thread t2 = new Thread(new EvenOddTask(print, 10, true));
    t1.start();
    t2.start();
  }
}


class EvenOddTask implements Runnable {
  private int max;
  private Output print;
  private boolean isEvenNumber;

  EvenOddTask(Output print, int max, boolean isEvenNumber) {
    this.print = print;
    this.max = max;
    this.isEvenNumber = isEvenNumber;
  }

  @Override
  public void run() {
    int number = isEvenNumber == true ? 2 : 1;
    while (number <= max) {
      if (isEvenNumber) {
        print.printEven(number);
      } else {
        print.printOdd(number);
      }
      number += 2;
    }
  }
}


class Output {
  boolean isOdd = false;

  public synchronized void printEven(int number) {
    while (isOdd == false) {
      try {
        wait();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    System.out.println("Even:" + number);
    isOdd = false;
    notifyAll();
  }

  public synchronized void printOdd(int number) {
    while (isOdd == true) {
      try {
        wait();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    System.out.println("Odd:" + number);
    isOdd = true;
    notifyAll();
  }
}

I wanted to check whether there is any better or simple way to do these kind of tasks in Java 7. In general instead of using another Output class, can I not print out directly in EvenOddTask class?


Solution

  • You can do so in the following ways :

    1. Without using synchronization :

      class Print {
      
          private static int count = 1;
          private static int MAX = 20;
          private boolean isOdd = true;
      
          public void printEven() {
              while (true) {
                  if (count > MAX) break;
                  if (!isOdd) {
                      System.err.println(Thread.currentThread().getName() + ":" + count++);
                      isOdd = true;
                  }
              }
          }
      
          public void printOdd() {
              while (true) {
                  if (count > MAX) break;
                  if (isOdd) {
                      System.err.println(Thread.currentThread().getName() + ":" + count++);
                      isOdd = false;
                  }
              }
          }
      
      }
      
      public class ThreadOddEven {
          public static void main(String[] args) {
              Print p = new Print();
      
              // Thread t1 = new Thread(() -> p.printEven());
              Thread t1 = new Thread(new Runnable() {     
                 @Override
                 public void run() {
                    p.printEven();                
                 }
              });
              t1.setName("EVEN");
      
              // Thread t2 = new Thread(() -> p.printOdd());
              Thread t2 = new Thread(new Runnable() {
                 @Override
                 public void run() {
                    p.printOdd(); 
                 }
              });
              t2.setName("ODD");
      
              t1.start();
              t2.start();
          }
      
      }
      

      This is probably the most easiest way to achieve printing odd and even numbers across two threads.

      Here we are just using a boolean variable isOdd. This value gets toggled after each thread prints a value.

    2. Using synchronization :

      class Print2 {
      
          private static int count = 1;
          private static int MAX = 10;
          private Object obj = new Object();
      
          public void printEven() {
              while (true) {
                  if (count > MAX) break;
                  synchronized (obj) {
                      System.err.println(Thread.currentThread().getName() + " : " + count++);
                      obj.notify();
                      try {
                          obj.wait();
                      } catch (InterruptedException e) { }
                  }
              }
          }
      
          public void printOdd() {
              while (true) {
                  if (count > MAX) break;
                  synchronized (obj) {
                      System.err.println(Thread.currentThread().getName() + " : " + count++);
                      obj.notify();
                      try {
                          obj.wait();
                      } catch (InterruptedException e) { }
                  }
              }
          }
      
      }
      

      In the second example instead of using a boolean variable, we are using an object so that we can synchronize the calls between both threads.

      The main method call to this class is the same as the above example.