线程交替打印需要用到线程通信的知识。其他的方法我不太了解,首先想到的就是用Condition来实现线程之间的通信。刚开始写好代码,本地运行,多组测试结果什么的都正确,但是一到线上运行,打印的结果就是乱的,之前从来没有遇到过这种情况,想了我一个多小时。最后突然想到测试用例输入的时候和在本地运行输入的情况有点不一样。因为需要多组测试,所以需要定义一个while(scanner.hasNext()){...}的循环体。本地测试由于是我们手动输入的,在下一次输入之前,前一次的打印结果就已经全部结束了(四个线程已经运行结束)。但是线上是机器测试的,可能前一次的测试还没打印结束,下一次的测试又开始了,所以会导致两次的测试数据会穿插在一起。
知道了原因,就好办了,只要做到每一次测试打印结束后while(){}循环才能结束,首先想到的就是用CountdownLatch。每次while循环开始就定义一个countdownLatch(4),每个线程结束后计数器就减一,减到0后再进行下一组数据的测试。
代码如下:

import java.util.Scanner;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 多线程,线程交替打印ABCDABCD
 */
public class Test49 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            int n = scanner.nextInt();
            CountDownLatch countDownLatch = new CountDownLatch(4);
            AlternativePrint alternativePrint = new AlternativePrint();
            //创建四个线程
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        for (int i = 0; i < n; i++) {
                            alternativePrint.printA();
                        }
                    } finally {
                        countDownLatch.countDown();
                    }
                }
            }).start();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        for (int i = 0; i < n; i++) {
                            alternativePrint.printB();
                        }
                    } finally {
                        countDownLatch.countDown();
                    }
                }
            }).start();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        for (int i = 0; i < n; i++) {
                            alternativePrint.printC();
                        }
                    } finally {
                        countDownLatch.countDown();
                    }
                }
            }).start();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        for (int i = 0; i < n; i++) {
                            alternativePrint.printD();
                        }
                    } finally {
                        countDownLatch.countDown();
                    }
                }
            }).start();
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println();
        }
    }
}

class AlternativePrint {
    private Lock lock = new ReentrantLock();
    private Condition conditionA = lock.newCondition();
    private Condition conditionB = lock.newCondition();
    private Condition conditionC = lock.newCondition();
    private Condition conditionD = lock.newCondition();
    private int number = 1;

    void printA() {
        lock.lock();
        try {
            if (number != 1) {
                conditionA.await();
            }
            System.out.print("A");
            //"A"打印结束,标记置为2,并唤醒打印"B"的线程
            number = 2;
            conditionB.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    void printB() {
        lock.lock();
        try {
            if (number != 2) {
                conditionB.await();
            }
            System.out.print("B");
            //"B"打印结束,标记置为3,并唤醒打印"C"的线程
            number = 3;
            conditionC.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    void printC() {
        lock.lock();
        try {
            if (number != 3) {
                conditionC.await();
            }
            System.out.print("C");
            //"C"打印结束,标记置为4,并唤醒打印"D"的线程
            number = 4;
            conditionD.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    void printD() {
        lock.lock();
        try {
            if (number != 4) {
                conditionD.await();
            }
            System.out.print("D");
            //"D"打印结束,标记置为1,并唤醒打印"A"的线程
            number = 1;
            conditionA.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}