【线程】wait()+notifyAll()实现多个线程交替遍历,输出ABCABC

背景

有三个线程,每个线程分别循环输出A、B、C,各线程循环10次,要求输出结果是ABCABCABC这样的

代码

java 复制代码
@Data
public class PrintThread extends Thread {
    private String string;               // 输出的字符串
    private int order;                   // 输出的顺序
    private static Object lock;          // 静态锁对象
    private static volatile int index = 0; // 共享的索引变量

    public PrintThread(String string, int order, Object lock) {
        this.string = string;
        this.order = order;
        this.lock = lock;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            synchronized (lock) {  // 使用锁对象进行同步
                while (index % 3 != order) {  // 判断是否轮到当前线程输出
                    try {
                        lock.wait();  // 如果不是轮到当前线程输出,则释放锁并等待
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                try {
                    Thread.sleep(10);  // 模拟输出过程的耗时操作
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                index++;  // 修改索引变量,表示下一个线程可以输出了
                System.out.println(string);  // 输出字符串
                lock.notifyAll();  // 唤醒其他等待的线程
            }
        }
    }

    public static void main(String[] args) {
        try {
            Object lock = new Object();  // 创建锁对象
            PrintThread threadA = new PrintThread("A", 0, lock);  // 创建线程A
            PrintThread threadB = new PrintThread("B", 1, lock);  // 创建线程B
            PrintThread threadC = new PrintThread("C", 2, lock);  // 创建线程C
            threadA.start();  // 启动线程A
            threadB.start();  // 启动线程B
            threadC.start();  // 启动线程C
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

最后

实际会有这样的场景吗?下面举几个例子

1、假设在一个食堂,有很多人在排队打饭,每个人需要完成以下步骤:先拿餐具,然后拿菜,再拿饭,最后付钱。

2、多线程下载器。当我们下载一个大文件时,可以使用多个线程同时从不同的服务器上下载文件的不同部分,然后将这些部分合并成一个完整的文件。通过多个线程交替遍历不同的服务器,可以提高下载速度,加快文件的下载过程。

3、医院的门诊、机场的登机口、超市的收银台等等。

扩展

除了wait+notifyAll,还有其他的实现方式

  1. 使用CountDownLatchCountDownLatch是一个同步辅助类,可以用于控制一个或多个线程等待其他线程完成操作。它通过一个计数器来实现,线程调用await()方法等待计数器变为0,而其他线程调用countDown()方法来减少计数器的值。当计数器变为0时,等待的线程将被唤醒。

  2. 使用CyclicBarrierCyclicBarrier也是一个同步辅助类,可以用于多个线程之间的同步。它和CountDownLatch类似,都是通过计数器来实现线程的等待和唤醒。不同之处在于,CyclicBarrier的计数器可以重复使用,当计数器减为0时,所有等待的线程都会被唤醒,并且计数器会被重置为初始值。

  3. 使用SemaphoreSemaphore是一个计数信号量,可以用来控制同时访问某个资源的线程个数。它维护了一个许可证的计数器,线程可以通过acquire()方法获取许可证,如果计数器大于0,线程可以继续执行;如果计数器为0,线程将被阻塞。线程在使用完资源后,需要调用release()方法释放许可证,使得其他线程可以继续访问资源。

  4. 使用LockConditionLock是一个可重入的互斥锁,可以用来替代synchronized关键字实现线程的同步。Condition是与Lock相关联的条件对象,可以用来实现线程的等待和唤醒。线程可以通过调用await()方法等待条件满足,而其他线程可以通过调用signal()signalAll()方法来唤醒等待的线程。

相关推荐
骄马之死4 小时前
SpringMVC + SpringBoot 核心知识点总结
java·spring boot·后端
郑洁文5 小时前
基于Spring Boot的流浪动物救助网站
java·spring boot·后端·毕设·流浪动物救助
螺丝钉code6 小时前
JAVA项目 Claude code CLAUDE.md 到底应该怎么写
java·人工智能·claude code
摇滚侠7 小时前
Maven 入门+高深 单一架构案例 54-59
java·架构·maven·intellij-idea
VidDown8 小时前
Webhook 调试器:让第三方回调“原形毕露”
java·开发语言·javascript·编辑器·postman
折哥的程序人生 · 物流技术专研8 小时前
Java 23 种设计模式:从踩坑到精通 | 原型模式 —— 克隆对象,深拷贝与浅拷贝的坑你踩过吗?
java·设计模式·架构·原型模式·单一职责原则
装不满的克莱因瓶8 小时前
基于 OpenResty 扩展开发实现动态服务注册与发现能力
java·开发语言·架构·openresty
程序员小羊!8 小时前
06Java 异常机制与常用类
java
weixin_523185329 小时前
Java基础知识总结(四):引用数据类型与参数传递机制
java·开发语言·python
宸津-代码粉碎机9 小时前
Spring AI企业级实战|从RAG优化到Agent多工具调度
java·大数据·人工智能·后端·python·spring