刚开始a、b、c、d的等待池中都没有ABCD四个线程,所以ABCD都有机会执行打印方法里打同步代码

A线程执行打印完毕调用b.notify()从b的等待池的中移走一个线程,a.wait()进入a的等待池(a对象等待池:A线程)
B线程执行打印完毕调用c.notify()从b的等待池的中移走一个线程,b.wait()进入a的等待池(b对象等待池:B线程)
C线程执行打印完毕调用d.notify()从b的等待池的中移走一个线程,c.wait()进入a的等待池(c对象等待池:C线程)
D线程执行打印完毕调用a.notify()从b的等待池的中移走一个线程,d.wait()进入a的等待池(d对象等待池:D线程,a对象等待池:没有A线程)
D线程执行完后a和b线程池里都没有A线程,而BCD线程都不能同时获取它们执行打印所需要的两个对象锁标记,所以此时只有A线程能执行打印,
A线程第二次打印往后把b对象等待池的一个线程移走,因为b的等待池只有B线程,所以B线程被移走放入锁池,此时只有B线程能执行打印,以此类推,B打印后只能执行C,C打印后只能执行D,D打印后只能执行A...

因为刚开始一起启用四个线程后不知道哪个线程会先执行打印,所以需要控制线程启动后的首次执行顺,我的做法是在创建线程的类里加两个静态整型变量newIndex和runIndex,每当创建线程的对象是就把当前线程的Id设为newIndex的值,然后newIndex加1,每个线程首次执行打印后都把runIndex加1,当线程执行到synchronized里先判断当前线程的id是否大于runIndex,如果大于说明这个线程是首次执行且还不应该到它执行打印,所以把它在外层synchronized的对象上休眠等待它上一个线程执行答应后唤醒它。

每次一个线程打印完后就休眠了,为了控制每个线程打印完了最后一次直接结束而不是进入休眠所以在打印后需要判断一下是否当前线程已经完成了所以打印次数。

import java.util.Scanner;

/**
 * 题目描述
 * 问题描述:有4个线程和1个公共的字符数组。
 * 线程1的功能就是向数组输出A,线程2的功能就是向字符输出B,线程3的功能就是向数组输出C,
 * 线程4的功能就是向数组输出D。要求按顺序向数组赋值ABCDABCDABCD,ABCD的个数由线程函数1的参数指定
 */
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()){
            int num = scanner.nextInt();
            Object a = new Object();
            Object b = new Object();
            Object c = new Object();
            Object d = new Object();
            Thread thread1 = new Thread(new ThreadPrintAbcd("A",a,b,num));
            Thread thread2 = new Thread(new ThreadPrintAbcd("B",b,c,num));
            Thread thread3 = new Thread(new ThreadPrintAbcd("C",c,d,num));
            Thread thread4 = new Thread(new ThreadPrintAbcd("D",d,a,num));

            thread1.start();
            thread2.start();
            thread3.start();
            thread4.start();
        }
    }
}
class ThreadPrintAbcd implements Runnable{
    private static int newIndex=0;
    private static int runIndex=0;
    private boolean isFirstRun=true;
    private Object self;
    private Object next;
    private String name;
    private int id;
    private int num;

    public ThreadPrintAbcd(String name,Object self,Object next,int num){
        id = newIndex++;
        this.name = name;
        this.self = self;
        this.next = next;
        this.num = num;
    }
    @Override
    public void run() {
        while (num > 0){
        synchronized(self){
                if(id > runIndex){
                    try {
                        self.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.print(name);
                if(isFirstRun){
                    runIndex ++;
                    isFirstRun=false;
                }
            synchronized (next) {
                next.notify();
            }
                num--;
                if(num >0){
                    try {
                        self.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}