手撕面试题:多线程交叉打印ABC

本文展示了使用synchronized、wait/notifyAll、Lock和Condition四个Java并发工具在PrintABCUsingWaitNotify,PrintABCUsingLock和PrintABCUsingLockCondition类中如何实现三个线程交替打印A、B、C,确保按顺序输出指定次数的字符串。
摘要由CSDN通过智能技术生成

三个线程分别打印 A,B,C,要求这三个线程一起运行,打印 n 次,输出形如“ABCABCABC…”的字符串

💖 synchronized + wait + notifyAll 实现

PrintABCUsingWaitNotify.java

public class PrintABCUsingWaitNotify {

    private int state;// 状态对应需要打印值:0:A,1:B,2:C
    private int times;// 需要打印的次数
    private final Object LOCK = new Object();//共用一个锁

    public PrintABCUsingWaitNotify(int times) {
        this.times = times;
    }

    public static void main(String[] args) {
        PrintABCUsingWaitNotify printABC = new PrintABCUsingWaitNotify(3);
        new Thread(() -> {
            printABC.printLetter("A", 0);
        }, "A").start();
        new Thread(() -> {
            printABC.printLetter("B", 1);
        }, "B").start();
        new Thread(() -> {
            printABC.printLetter("C", 2);
        }, "C").start();
    }

    private void printLetter(String s, int targetState) {
        for(int i = 0; i < times; i++)//保证每个线程打印 times 次
        {
            synchronized (LOCK)// 获取锁 避免插队
            {
                while (state % 3 != targetState){// 打印之前,先判断是否符合打印条件,即是否轮到此线程打印了
                    try {
                        LOCK.wait();// 没轮到 则释放锁并等待
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
                System.out.println(s);// 终于等到了
                state++;
                LOCK.notifyAll();//唤醒等待中的锁
            }
        }
    }
}

💖 Lock 实现

PrintABCUsingLock.java

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class PrintABCUsingLock {

    private int times; // 控制打印次数
    private int state;  // 状态对应需要打印值:0:A,1:B,2:C
    private Lock lock = new ReentrantLock();

    public PrintABCUsingLock(int times) {
        this.times = times;
    }

    private void printLetter(String s, int targetNum) {
        int cnt = 0;//统计打印了多少次
        while(cnt < times)
        {
            lock.lock();//先获取锁(保证输出和状态更新的原子性)
            if(state % 3 == targetNum)// 符合条件才输出,不符直接跳过
            {
                System.out.print(s);
                state++;
                cnt++;
            }
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        PrintABCUsingLock loopThread = new PrintABCUsingLock(3);

        new Thread(() -> {
            loopThread.printLetter("A", 0);
        }, "A").start();

        new Thread(() -> {
            loopThread.printLetter("B", 1);
        }, "B").start();

        new Thread(() -> {
            loopThread.printLetter("C", 2);
        }, "C").start();
    }
}

💖 Condition

PrintABCUsingLockCondition.java

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

/**
 * @author : lighting
 */
public class PrintABCUsingLockCondition {
    private int times;
    private int state;

    private static Lock lock = new ReentrantLock();

//    三个Condition休息区分别对应三个线程
    private static Condition c1 = lock.newCondition();
    private static Condition c2 = lock.newCondition();
    private static Condition c3 = lock.newCondition();

    public PrintABCUsingLockCondition(int times) {
        this.times = times;
    }

    /**
     * 
     * @param s 要输出的字符串
     * @param targetState 目标状态
     * @param cur 当前的 Condition(条件等待区)
     * @param next 下一个 Condition
     */
    private void printLetter(String s, int targetState, Condition cur, Condition next) {
        int cnt = 0;
        while(cnt < times){
            lock.lock();//老规矩先拿锁
            try {
                while (state % 3 != targetState) {
                    cur.await();//只要不符合条件就等待
                }
                System.out.println(s);
                cnt++;
                state++;
                next.signal();//唤醒下一个休息等待的 Condition
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                lock.unlock();//切记释放锁
            }
        }
    }

    public static void main(String[] args) {
        PrintABCUsingLockCondition print = new PrintABCUsingLockCondition(3);
        new Thread(() -> {
            print.printLetter("A", 0, c1, c2);
        }, "a").start();

        new Thread(() -> {
            print.printLetter("B", 1, c2, c3);
        }, "b").start();
        new Thread(() -> {
            print.printLetter("C", 2, c3, c1);
        }, "c").start();
    }
}

👨‍🏫 参考地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值