JAVA多线程打印ABC

这篇博客探讨了多线程环境下如何正确实现轮流打印ABC的问题。通过使用三个线程分别负责A、B、C的打印,确保按顺序进行。文章强调了在唤醒线程时加入if判断的重要性,以防止因随机唤醒导致的顺序错误,从而避免多线程同步的潜在问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多线程中一个很有名的例题就是多线程打印ABC,要求用三个线程,分别是打印A,打印B,打印C,轮流唤醒和锁死,最终打印出10ABC

/**
 * Created by 123 on 2016/8/30.
 */
public class PrintABC {
    public static void main(String[] args) {
        ABC p = new ABC('A');//以A作为开始
        new Print1(p).start();//启动打印A的线程,以p作为控制
        new Print2(p).start();
        new Print3(p).start();
    }
}

//将打印A,打印B,打印C分别列为三个互斥的方法,写在类ABC中

class ABC {
    char now;   //当前需要打印的字母是now

    public ABC(char now) {
        this.now = now;
    }

    public synchronized void PrintA() {    //打印A的方法,它与打印其它两个字母的方法互斥
        if (now != 'A') {                  //如果线程被唤醒后发现当前需要打印的字母不是A
            try {                          //就让这个线程wait(),继续进入等待池
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        if (now == 'A') {                   //如果当前需要打印的字母是A
            System.out.print('A');          //打印A
            now = 'B';                      //将需要打印的字母置为B
            Print1.cnt1--;                  //打印次数减1,cnt1是Print1中的静态变量
        }
        notify();                           //再从等待池中唤醒一个线程
    }

    public synchronized void PrintB() {     //同理
        if (now != 'B') {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        if (now == 'B') {
            System.out.print('B');
            now = 'C';
            Print2.cnt2--;
        }
        notify();
    }

    public synchronized void PrintC() {     //同理
        if (now != 'C') {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        if (now == 'C') {
            System.out.print('C');
            now = 'A';
            Print3.cnt3--;
        }
        notify();
    }
}

class Print1 extends Thread {       //打印A的线程
    ABC p = null;
    public static int cnt1=10;
    public Print1(ABC p) {
        this.p = p;
    }       //构造方法,将ABC那个类传进来
                                               //三个线程共用那一个类
    @Override
    public void run() {
        while (cnt1 > 0) {
            p.PrintA();                         //一直打印,打印十次
                                                //PrintA并不是打印了A,只是尝试打印A
                                                //cnt1--是在PrintA中确保打印成功了以后再执行的
        }
    }
}

class Print2 extends Thread {                   //同理
    ABC p = null;
    public static int cnt2=10;
    public Print2(ABC p) {
        this.p = p;
    }

    @Override
    public void run() {
        while (cnt2 > 0) {
            p.PrintB();
        }
    }
}

class Print3 extends Thread {                   //同理
    ABC p = null;
    public static int cnt3=10;
    public Print3(ABC p) {
        this.p = p;
    }

    @Override
    public void run() {
        while (cnt3 > 0) {
            p.PrintC();
        }
    }
}

由于notify的唤醒是随机的,所以如果这里不加if判断的话,可能打印完A后唤醒了打印C的线程,这样就wait()完了以后就又打印了一个C,就乱套了,这就是多线程的一个Bug

 if (now == 'A') {                   //如果当前需要打印的字母是A
            System.out.print('A');          //打印A
            now = 'B';                      //将需要打印的字母置为B
            Print1.cnt1--;                  //打印次数减1,cnt1是Print1中的静态变量
        }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值