Once an interviewer asked such a question, how to make two threads alternately print odd and even numbers? How to make multiple threads execute alternately?
Before answering this question, we need to understand the running mechanism of java multithreading, inter thread communication mechanism, and thread synchronization.
I know there are two solutions to this problem, one is based on synchronized and wait/notify, the other is based on Lock and Condition
1. Based on synchronized and wait/notify
public class ChangeABC { private Object lock = new Object(); private boolean RUN0 = true; private static final int LIMIT = 10; public static void main(String[] args) throws InterruptedException { final ChangeABC o = new ChangeABC(); new Thread(new Runnable() { @Override public void run() { try { o.m0(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "t0").start(); new Thread(new Runnable() { @Override public void run() { try { o.m1(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "t1").start(); Thread.sleep(10 * 1000); } private void m1() throws InterruptedException { for (int i = 1; i < LIMIT; i += 2) { synchronized (lock) { if (RUN0) { lock.wait(); } System.out.println(Thread.currentThread().getName() + "___" + i); RUN0 = true; lock.notify(); } } } private void m0() throws InterruptedException { for (int i = 0; i < LIMIT; i += 2) { synchronized (lock) { if (!RUN0) { lock.wait(); } System.out.println(Thread.currentThread().getName() + "___" + i); RUN0 = false; lock.notify(); } } } }
2. Based on Lock and Condition
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /*** Inter thread communication - lock based condition * @ date December 21, 2017*/ public class ChangeABC1 { private Lock lock = new ReentrantLock(); private Condition c0 = lock.newCondition(); private Condition c1 = lock.newCondition(); private Condition c2 = lock.newCondition(); private int status = 0; private static final int LIMIT = 10; public static void main(String[] args) throws InterruptedException { ExecutorService exec = new ThreadPoolExecutor(3, 30, 60, TimeUnit.SECONDS, new LinkedBlockingQueue(300), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); final ChangeABC1 o = new ChangeABC1(); exec.submit(o.createTask(0)); exec.submit(o.createTask(1)); exec.submit(o.createTask(2)); exec.shutdown(); exec.awaitTermination(5, TimeUnit.MINUTES); } /*** @param name* @param i*/ private Runnable createTask(final int i) { return new Runnable() { @Override public void run() { try { m(i); } catch (InterruptedException e) { e.printStackTrace(); } } }; } private void m(final int n) throws InterruptedException { for (int i = n; i < LIMIT; i += 3) { lock.lock(); try { switch (n) { case 0: if (status != 0) { c0.await(); } System.out.println(Thread.currentThread().getName() + "___" + i); status = 1; c1.signal(); break; case 1: if (status != 1) { c1.await(); } System.out.println(Thread.currentThread().getName() + "___" + i); status = 2; c2.signal(); break; case 2: if (status != 2) { c2.await(); } System.out.println(Thread.currentThread().getName() + "___" + i); status = 0; c0.signal(); break; default: break; } } finally { lock.unlock(); } } } }