问题:如何实现三个线程交替循环打印?

示例:线程1打印A,线程2打印B,线程3打印C,要求交替打印,并且能够循环打印。
输入后果相似:ABCABCABC

这道题的难度是五颗星,在面试中也会常常遇到,如果是第一次见到这道题,很难在短时间内想出正当的解决方案。
如果只要求交替打印一次的话,实现比较简单,能够用Thread.join()办法,一个线程期待另一个线程执行实现。
当初要求循环打印,就波及线程间通信,必须要用到锁,一把锁必定不够。例如线程1开释锁之后,线程2和线程3都可能获取到锁,是随机的,当初要求必须是线程2获取到锁,所以须要三把锁。

执行过程:
线程1获取A锁,打印A,开释B锁;
线程2获取B锁,打印B,开释C锁;
线程3获取C锁,打印C,开释A锁;
循环执行;

能够用Synchronized或者ReentrantLock实现,不过它们不能控制线程启动后的执行程序。因为三个线程启动后,都期待CPU调度执行,而CPU调度的程序又是随机的,所以不能保障线程1先执行。

有个能够控制线程启动后执行程序,又简略的实现形式,就是用Semaphore(信号量),它能够管制共享资源的拜访个数。

应用形式:

  1. 初始化的时候,指定共享资源的个数

    // 初始化一个资源Semaphore semaphore = new Semaphore(1);
  2. 获取资源,获取资源后,semaphore资源个数减1,变成0,其余线程再获取资源的时候就会阻塞期待
semaphore.acquire();
  1. 开释资源,semaphore资源个数加1,其余阻塞的线程就能够获取到资源了
semaphore.release();

代码实现:

/** * @author yideng * @apiNote 三个线程循环打印 */public class CirclePrint {    static class ThreadDemo extends Thread {        private Semaphore current;        private Semaphore next;        private String name;        /**         * 构造方法         * @param current 要获取的以后锁         * @param next    要开释的下一把锁         * @param name    打印内容         */        public ThreadDemo(Semaphore current, Semaphore next, String name) {            this.current = current;            this.next = next;            this.name = name;        }        @Override        public void run() {            for (int i = 0; i < 5; i++) {                try {                    // 获取以后锁,而后打印                    current.acquire();                    System.out.print(name);                } catch (InterruptedException e) {                    e.printStackTrace();                }                // 开释下一把锁                next.release();            }        }    }    public static void main(String[] args) {        // 初始化三把锁,只有A锁是可用的        Semaphore A = new Semaphore(1);        Semaphore B = new Semaphore(0);        Semaphore C = new Semaphore(0);        // 创立并启动三个线程,线程1获取A锁,开释B锁        new ThreadDemo(A, B, "A").start();        // 线程2获取B锁,开释C锁        new ThreadDemo(B, C, "B").start();        // 线程3获取C锁,开释A锁        new ThreadDemo(C, A, "C").start();    }}

输入后果:

ABCABCABCABCABC

你感觉怎么样?有更简略的解决方案吗?