交替打印 ABC

如题。本文给出交替打印的代码示例,并解释了条件变量在代码实现中所起的作用。

使用三个线程,一个只负责打印A,另一个只负责打印B,最后一个只负责打印C
按顺序交替。即打印A后,才能打印B,打印B后,才能打印C
由于按序交替,最好采用条件队列来实现。初始时,只有打印A的条件满足 打印B、C的条件都不满足。A打印后,使得打印B的条件满足,同时打印A的条件由原来的满足变成不满足;B打印后,使得打印C的条件满足,同时打印B的条件由原来的满足变成不满足;C打印后,使得打印A的条件满足,同时打印C的条件由原来的满足变成不满足。

采用锁+条件队列实现的优势:
锁+条件队列是基于"通知-唤醒"机制实现的,比sleep+轮询的方式要高效。

完整代码如下:

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

/**
 * @author psj
 * @date 20-3-7
 */
public class PrintABC {
    private ReentrantLock lock = new ReentrantLock();
    //与锁关联的条件队列,当打印条件不满足时,挂起线程(通知唤醒机制,而不是sleep或者轮询)
    private Condition printA = lock.newCondition();
    private Condition printB = lock.newCondition();
    private Condition printC = lock.newCondition();

    //初始化 打印A的条件成立,打印B不成立,打印C不成立
    private volatile boolean isA = true;
    private volatile boolean isB = false;
    private volatile boolean isC = false;


    public static void main(String[] args) {
        PrintABC pabc = new PrintABC();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        pabc.printA();
                    } catch (InterruptedException e) {
                        System.out.println(Thread.currentThread().getName() + " 退出打印");
                        break;
                    }
                }
            }
        }, "t1");

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        pabc.printB();
                    } catch (InterruptedException e) {
                        //响应中断退出打印
                        System.out.println(Thread.currentThread().getName() + " 退出打印");
                        break;
                    }
                }
            }
        }, "t2");

        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        pabc.printC();
                    } catch (InterruptedException e) {
                        System.out.println(Thread.currentThread().getName() + " 退出打印");
                        break;
                    }
                }
            }
        }, "t3");

        t2.start();
        t3.start();
        t1.start();


//        sleepMills(10 * 1000);
//        t1.interrupt();
    }

    public void printA() throws InterruptedException{
        try {
            lock.lock();
            while (!isA) {
                printA.await();
            }
            System.out.println(Thread.currentThread().getName() + " print A");
            sleepMills(2000);
            //A 已打印,将打印A的条件由原来的满足变成不满足
            isA = false;
            //将打印B的条件变成满足
            isB = true;
            //通知线程打印B
            printB.signal();
        }finally {
            lock.unlock();
        }
    }

    public void printB()throws InterruptedException {
        try {
            lock.lock();
            while (!isB) {
                printB.await();
            }
            System.out.println(Thread.currentThread().getName() + " print B");
            //模拟方法执行耗时
            sleepMills(2000);
            //打印B的条件由满足变成不满足
            isB = false;
            //使得打印C的条件变成满足
            isC = true;
            printC.signal();
        }finally {
            lock.unlock();
        }
    }

    public void printC()throws InterruptedException {
        try {
            lock.lock();
            while (!isC) {
                printC.await();
            }
            System.out.println(Thread.currentThread().getName() + " print C");
            sleepMills(2000);
            //C已打印,将打印C的条件由原来的满足变成不满足
            isC = false;
            //将打印A的条件变成满足
            isA = true;
            printA.signal();
        }finally {
            lock.unlock();
        }
    }

    private static void sleepMills(long mills) {
        try {
            TimeUnit.MILLISECONDS.sleep(mills);
        } catch (InterruptedException e) {
            System.out.println(e);
        }
    }
}
posted @ 2023-06-24 18:02  大熊猫同学  阅读(90)  评论(0编辑  收藏  举报