【线程】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()方法来唤醒等待的线程。

相关推荐
带刺的坐椅20 分钟前
Solon v3.4.7, v3.5.6, v3.6.1 发布(国产优秀应用开发框架)
java·spring·solon
四谎真好看2 小时前
Java 黑马程序员学习笔记(进阶篇18)
java·笔记·学习·学习笔记
桦说编程2 小时前
深入解析CompletableFuture源码实现(2)———双源输入
java·后端·源码
java_t_t2 小时前
ZIP工具类
java·zip
lang201509282 小时前
Spring Boot优雅关闭全解析
java·spring boot·后端
pengzhuofan3 小时前
第10章 Maven
java·maven
百锦再4 小时前
Vue Scoped样式混淆问题详解与解决方案
java·前端·javascript·数据库·vue.js·学习·.net
刘一说4 小时前
Spring Boot 启动慢?启动过程深度解析与优化策略
java·spring boot·后端
壹佰大多4 小时前
【spring如何扫描一个路径下被注解修饰的类】
java·后端·spring
百锦再4 小时前
对前后端分离与前后端不分离(通常指服务端渲染)的架构进行全方位的对比分析
java·开发语言·python·架构·eclipse·php·maven