Ping Pong using Threads in Java Ping Pong using Threads in Java

Page content

This problem is frequently asked in the interview to check your understanding on threads and your programming skills. Problem statement might change for e.g.

  • Print ping pong using two threads.
  • Print alternate number using two threads.
  • Print even numbers by one thread and odd numbers by another thread.

Using Wait Notify

We can print the “Ping Pong” alternatively using Wait Notify. This is what happen behind the scene:-

  1. 1st thread print “Ping” and go to wait state.
  2. 2nd thread wakes up from wait state, print “Ping”, notify 1st thread, goes back to wait state.
  3. 1st thread wakes up from wait state, print “Pong”, notify 2nd thread, goes back to wait state.
  4. Step 2 and 3 repeats and print “Ping Pong” alternatively.
package com.abc;

public class PingPong {
  public static void main(String[] args) {
    Object LOCK_OBJECT = new Object();
    Thread ping = new Thread(new PingPongThread(LOCK_OBJECT, "Ping"));
    Thread pong = new Thread(new PingPongThread(LOCK_OBJECT, "Pong"));
    ping.start();
    pong.start();
  }
}

class PingPongThread implements Runnable{

  private Object LOCK_OBJECT;
  private String name;

  public PingPongThread(Object LOCK_OBJECT, String name) {
    this.LOCK_OBJECT = LOCK_OBJECT;
    this.name = name;
  }

  @Override
  public void run() {
    synchronized (LOCK_OBJECT) {
      while(true) {
        System.out.println(name);

        try {
          Thread.sleep(1000);
        } catch (InterruptedException e1) {
          e1.printStackTrace();
        }
        LOCK_OBJECT.notify();

        try {
          LOCK_OBJECT.wait(1000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    }
  }
}
Output
Ping Pong Ping Pong ... ...

Things to note in above program:

  1. wait() and notify() are Object’s method so you need to create a LOCK_OBJECT to call these methods. You pass this LOCK_OBJECT from constructor. Both threads try to acquire a lock on LOCK_OBJECT, when one thread is having lock on this object, other thread can not access the resources.
  2. wait() and notify() methods can only be called within the Synchronized Block.
  3. wait() and sleep() method throw InterruptedException exception.
  4. You can remove the sleep() method call from this program. This is called to add 1 sec interval in printing “Ping” and “Pong” so that we can verify this in console.

Using ReentrantLock Condition

ReentrantLock locks are new in Java, which provide Condition having two methods await() and signal(). These two methods works very similar to Object’s wait() and notify() methods with more flexibility.

In this program we’ll print “Ping” and “Pong” alternatively exactly N number of times and stop the threads.

package com.example.thread;

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

public class PingPongUsingReentrantCondition {

	private static ReentrantLock lock = new ReentrantLock(true);
	private Condition conditionMet = lock.newCondition();

	public static void main(String[] args) {
		PingPongUsingReentrantCondition pingPong = new PingPongUsingReentrantCondition();
		int times = 5;
    System.out.println("N = " + times);
		Thread t1 = new Thread(() -> pingPong.pingpong("Ping!", times));
		Thread t2 = new Thread(() -> pingPong.pingpong("Pong!", times));
		t1.start();
		t2.start();
	}
	
	public void pingpong(String s, int times) {
		int counter = 1;
		while(counter<=times) {				
			run(s, counter);
			counter = counter+1;
		}
	}

	public void run(String s, int counter) {
		lock.lock();
		try {
			conditionMet.await(2, TimeUnit.SECONDS);
			System.out.println(s + "(" + counter + ")");
			conditionMet.signal();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}
}
Output
N = 5 Ping!(1) Pong!(1) Ping!(2) Pong!(2) Ping!(3) Pong!(3) Ping!(4) Pong!(4) Ping!(5) Pong!(5)