重学java 43.多线程 多等待多唤醒案例

Fear never builds the future,but hope does.

                                                          —— 24.5.25

多等待多唤醒问题

        在多条线程同时消费同时等待时,会出现问题

BaoZiPu

package S77ThreadMoreWait;

/*
    count和flag可以定义成包装类,但要记得给count和flag手动赋值
    不然对于本案例来说,容易出现空指针异常
 */
public class BaoZiPu {
    // 包子的数目count
    private int count;
    // 是否有包子flag
    private boolean flag;

    public BaoZiPu() {
    }

    public BaoZiPu(int count, boolean flag) {
        this.count = count;
        this.flag = flag;
    }

    // getCount改成消费包子,直接输出包子数量count
    public void getCount() {
        System.out.println("消费了第"+count+"个包子");
    }

    // setCount改造成生产包子,count++
    public void setCount() {
        count++;
        System.out.println("生产了第"+count+"个包子");
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}

生产product线程

package S77ThreadMoreWait;

// 实现Runnable接口
public class Product implements Runnable{
    BaoZiPu baoZiPu = new BaoZiPu();

    // 提供一个有参构造
    public Product(BaoZiPu baoZiPu){
        this.baoZiPu = baoZiPu;
    }
    @Override
    public void run() {
        // 定义一个死循环
        while(true) {
            try {
                Thread.sleep(100L);
            }catch (InterruptedException e){
                throw new RuntimeException(e);
            }


            // 同步代码块
            synchronized (baoZiPu){
                // 1.判断flag是否为true,如果是true,证明有包子,生产线程等待
                if(baoZiPu.isFlag()==true){
                    try{
                        baoZiPu.wait();
                    }catch(InterruptedException e){
                        throw new RuntimeException(e);
                    }
                }

                // 2.如果flag为false,证明没有包子,则要开始生产
                baoZiPu.setCount();
                // 3.改变flag为true
                baoZiPu.setFlag(true);
                // 4.唤醒所有等待线程
                baoZiPu.notify();
            }
        }
    }
}

消费consumer线程

package S77ThreadMoreWait;

public class Consumer implements Runnable{
    BaoZiPu baoZiPu = new BaoZiPu();

    // 提供一个有参构造
    public Consumer(BaoZiPu baoZiPu){
        this.baoZiPu = baoZiPu;
    }

    @Override
    public void run() {
        while(true) {
            try {
                Thread.sleep(100L);
            }catch (InterruptedException e){
                throw new RuntimeException(e);
            }

            // 同步代码块
            synchronized (baoZiPu){
                // 1.判断flag是否为false,如果是false,证明没有包子,消费线程等待
                if(baoZiPu.isFlag()==false){
                    // 抛出异常
                    try{
                        baoZiPu.wait();
                    }catch(InterruptedException e){
                        throw new RuntimeException(e);
                    }
                }

                // 2.如果flag为true,则要开始消费
                baoZiPu.getCount();
                // 3.改变flag为false,消费完了,没有包子了
                baoZiPu.setFlag(false);
                // 4.唤醒所有等待线程
                baoZiPu.notify();
            }
        }
    }
}

测试类

package S77ThreadMoreWait;


public class Demo216Test {
    public static void main(String[] args) {
        // 变成同一个对象
        BaoZiPu baoZiPu = new BaoZiPu();

        // 把baozipu对象分别传给两个线程中
        Product product = new Product(baoZiPu);
        Consumer consumer = new Consumer(baoZiPu);

        // 三条生产线程
        new Thread(product).start();
        new Thread(product).start();
        new Thread(product).start();
        // 三条消费线程
        new Thread(consumer).start();
        new Thread(consumer).start();
        new Thread(consumer).start();
    }
}

运行结果:会出现连续生产和连续消费的行为

         多条线程在同时等待时,上一条线程结束之后会随机唤醒一条线程,所以不能确定具体的顺序 

解决尝试 — 唤醒全部线程 notifyAll

   生产线程Product

package S77ThreadMoreWait;

// 实现Runnable接口
public class Product implements Runnable{
    BaoZiPu baoZiPu = new BaoZiPu();

    // 提供一个有参构造
    public Product(BaoZiPu baoZiPu){
        this.baoZiPu = baoZiPu;
    }
    @Override
    public void run() {
        // 定义一个死循环
        while(true) {
            try {
                Thread.sleep(100L);
            }catch (InterruptedException e){
                throw new RuntimeException(e);
            }


            // 同步代码块
            synchronized (baoZiPu){
                // 1.判断flag是否为true,如果是true,证明有包子,生产线程等待
                if(baoZiPu.isFlag()==true){
                    try{
                        baoZiPu.wait();
                    }catch(InterruptedException e){
                        throw new RuntimeException(e);
                    }
                }

                // 2.如果flag为false,证明没有包子,则要开始生产
                baoZiPu.setCount();
                // 3.改变flag为true
                baoZiPu.setFlag(true);
                // 4.唤醒所有等待线程
                baoZiPu.notifyAll();
            }
        }
    }
}

   消费线程Consumer

package S77ThreadMoreWait;

public class Consumer implements Runnable{
    BaoZiPu baoZiPu = new BaoZiPu();

    // 提供一个有参构造
    public Consumer(BaoZiPu baoZiPu){
        this.baoZiPu = baoZiPu;
    }

    @Override
    public void run() {
        while(true) {
            try {
                Thread.sleep(100L);
            }catch (InterruptedException e){
                throw new RuntimeException(e);
            }

            // 同步代码块
            synchronized (baoZiPu){
                // 1.判断flag是否为false,如果是false,证明没有包子,消费线程等待
                if(baoZiPu.isFlag()==false){
                    // 抛出异常
                    try{
                        baoZiPu.wait();
                    }catch(InterruptedException e){
                        throw new RuntimeException(e);
                    }
                }

                // 2.如果flag为true,则要开始消费
                baoZiPu.getCount();
                // 3.改变flag为false,消费完了,没有包子了
                baoZiPu.setFlag(false);
                // 4.唤醒所有等待线程
                baoZiPu.notifyAll();
            }
        }
    }
}

  运行结果:会出现连续生产和连续消费的行为

解决尝试 — 把 if 改成 while

 生产线程Product

package S77ThreadMoreWait;

// 实现Runnable接口
public class Product implements Runnable{
    BaoZiPu baoZiPu = new BaoZiPu();

    // 提供一个有参构造
    public Product(BaoZiPu baoZiPu){
        this.baoZiPu = baoZiPu;
    }
    @Override
    public void run() {
        // 定义一个死循环
        while(true) {
            try {
                Thread.sleep(100L);
            }catch (InterruptedException e){
                throw new RuntimeException(e);
            }


            // 同步代码块
            synchronized (baoZiPu){
                // 1.判断flag是否为true,如果是true,证明有包子,生产线程等待
                while (baoZiPu.isFlag()==true){
                    try{
                        baoZiPu.wait();
                    }catch(InterruptedException e){
                        throw new RuntimeException(e);
                    }
                }

                // 2.如果flag为false,证明没有包子,则要开始生产
                baoZiPu.setCount();
                // 3.改变flag为true
                baoZiPu.setFlag(true);
                // 4.唤醒所有等待线程
                baoZiPu.notifyAll();
            }
        }
    }
}

 消费线程Consumer

package S77ThreadMoreWait;

public class Consumer implements Runnable{
    BaoZiPu baoZiPu = new BaoZiPu();

    // 提供一个有参构造
    public Consumer(BaoZiPu baoZiPu){
        this.baoZiPu = baoZiPu;
    }

    @Override
    public void run() {
        while(true) {
            try {
                Thread.sleep(100L);
            }catch (InterruptedException e){
                throw new RuntimeException(e);
            }

            // 同步代码块
            synchronized (baoZiPu){
                // 1.判断flag是否为false,如果是false,证明没有包子,消费线程等待
                while (baoZiPu.isFlag()==false){
                    // 抛出异常
                    try{
                        baoZiPu.wait();
                    }catch(InterruptedException e){
                        throw new RuntimeException(e);
                    }
                }

                // 2.如果flag为true,则要开始消费
                baoZiPu.getCount();
                // 3.改变flag为false,消费完了,没有包子了
                baoZiPu.setFlag(false);
                // 4.唤醒所有等待线程
                baoZiPu.notifyAll();
            }
        }
    }
}

 运行结果:不会出现连续生产和连续消费的行为

总结:notifyAll和while要一起执行,才可以保证我们的代码不会出现错误情况

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/641588.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TCN 问题汇总

config 代码 import osemotion ["Valence"]### For preprocessing ### If tagged with "# Check this", then its adjustable, otherwise leave it alone. config {"extract_class_label": 1,"extract_continuous_label": 1,"…

Linux之DMA驱动详解(2)-sun6i-dma.c 驱动为例

一、DMA控制器硬件 1.1 DMA寄存器 DMA控制器 一般都会包含以下寄存器: DMA硬件描述符地址寄存器:存放 DMA描述符 的地址。DMA配置寄存器:配置 DMA 的 burst 、 width 、 传输方向 等属性。DMA使能寄存器:使能 DMA通道DMA中断状…

LLM 大模型学习必知必会系列(十一):大模型自动评估理论和实战以及大模型评估框架详解

LLM 大模型学习必知必会系列(十一):大模型自动评估理论和实战以及大模型评估框架详解 0.前言 大语言模型(LLM)评测是LLM开发和应用中的关键环节。目前评测方法可以分为人工评测和自动评测,其中,自动评测技术相比人工…

暴雨“彩虹”行业大模型加速器平台全新发布

近日,在第七届数字中国建设峰会期间,暴雨信息全新发布“彩虹”行业大模型加速器平台,聚焦于为客户降本增效减负,将海量通用数据与行业特有数据融合,专注于流程工艺的智能化改进,因地制宜深挖业务需求&#…

第二十届文博会沙井艺立方分会场启幕!大咖齐打卡!

2024年5月24日-27日,第二十届中国(深圳)国际文化产业博览交易会沙井艺立方分会场活动将在艺立方非遗(文旅)产业园盛大举办。 本届文博会艺立方分会场活动办展特色鲜明,亮彩纷呈,将以“种下梧桐树…

win10无权禁用任务计划程序中的任务

问题说明 最近被win10的自动频繁更新搞得难受,发誓要彻底禁用这个家伙,于是网上找了教程执行,发现执行到禁用windows update计划任务时,提示: 这特么windows这个辣鸡系统,限制还真多!&#xf…

【Linux】信号>信号产生信号处理信号保存信号详解

主页:醋溜马桶圈-CSDN博客 专栏:Linux_醋溜马桶圈的博客-CSDN博客 gitee:mnxcc (mnxcc) - Gitee.com 目录 1.信号入门 1.1 生活角度的信号 1.2 技术应用角度的信号 1.3 信号概念 1.4 信号处理常见方式概览 2.产生信号 2.1 通过终端按键…

Redis 源码学习记录:集合 (set)

无序集合 Redis 源码版本:Redis-6.0.9,本篇文章无序集合的代码均在 intset.h / intset.c 文件中。 Redis 通常使用字典结构保存用户集合数据,字典键存储集合元素,字典值为空。如果一个集合全是整数,则使用字典国语浪费…

Python爬虫:爬取B站视频(最新、能用且讲解详细)【01】

📚博客主页:knighthood2001 ✨公众号:认知up吧 (目前正在带领大家一起提升认知,感兴趣可以来围观一下) 🎃知识星球:【认知up吧|成长|副业】介绍 ❤️如遇文章付费,可先看…

各位数字和-第13届蓝桥杯选拔赛Python真题精选

[导读]:超平老师的Scratch蓝桥杯真题解读系列在推出之后,受到了广大老师和家长的好评,非常感谢各位的认可和厚爱。作为回馈,超平老师计划推出《Python蓝桥杯真题解析100讲》,这是解读系列的第72讲。 各位数字和&#…

超简单白话文机器学习 - 回归树树剪枝(含算法介绍,公式,源代码实现以及调包实现)

1. 回归树 1.1 算法介绍 大家看到这篇文章时想必已经对树这个概念已经有基础了,如果不是很了解的朋友可以看看笔者的这篇文章: 超简单白话文机器学习-决策树算法全解(含算法介绍,公式,源代码实现以及调包实现&#x…

软件设计师备考笔记(十):网络与信息安全基础知识

文章目录 一、网络概述二、网络互连硬件(一)网络的设备(二)网络的传输介质(三)组建网络 三、网络协议与标准(一)网络的标准与协议(二)TCP/IP协议簇 四、Inter…

大模型再进化,实时互动成为未来核心能力

就在上周,OpenAI 又在 AI 湖面抛下一块大石,激起了千层浪:全新一代旗舰生成模型 GPT-4o 登场了。从现场演示来看,它与人类进行了一轮轮无缝衔接的对话,丝滑得就像真人,不仅响应时间极短,还能识别…

SkyWalking 介绍及部署

1、SkyWalking简介2、SkyWalking的搭建 2.1 部署Elasticsearch2.2 部署SkyWalking-Server2.3 部署SkyWalking-UI3、应用接入 3.1 jar包部署方式3.2 dockerfile方式3.3 DockerFile示例4、SkyWalking UI 界面说明 4.1 仪表盘 4.1.1 APM (1)全局维度&#x…

IDEA中好用的插件

IDEA中好用的插件 CodeGeeXMybatis Smart Code Help ProAlibaba Java Coding Guidelines​(XenoAmess TPM)​通义灵码常用操作 CodeGeeX 官网地址:https://codegeex.cn/ 使用手册:https://zhipu-ai.feishu.cn/wiki/CuvxwUDDqiErQUkFO2Tc4walnZY 安装完…

欣赏倪诗韵青桐断纹古琴很罕见:万中无一。

欣赏倪诗韵青桐断纹古琴很罕见:万中无一。龙池侧签海门倪诗韵制,带收藏证书此琴断纹优美如江面波光粼粼,为流水蛇腹断,是倪老师作品精品中的精品。细心的朋友可以看出倪老师在这张琴上题字非常小心认真。用一个词来形容——万中无…

【Unity2D:Animator】为角色添加动画效果

一、添加Animator组件并创建Animator Controller文件 1. 添加Animator组件: 2. 在Assets-Art文件夹中新建一个名为Animations的文件夹,用来存储所有动画资源 3. 在Animations文件夹中新建一个名为Player的文件夹,再创建一个名为Animators的文…

通过RAG架构LLM应用程序

在之前的博客文章中,我们已经描述了嵌入是如何工作的,以及RAG技术是什么。本节我们我们将使用 LangChain 库以及 RAG 和嵌入技术在 Python 中构建一个简单的 LLM 应用程序。 我们将使用 LangChain 库在 Python 中构建一个简单的 LLM 应用程序。LangChai…

白鹭群优化算法,原理详解,MATLAB代码免费获取

白鹭群优化算法(Egret Swarm Optimization Algorithm,ESOA)是一种受自然启发的群智能优化算法。该算法从白鹭和白鹭的捕食行为出发,由三个主要部分组成:坐等策略、主动策略和判别条件。将ESOA算法与粒子群算法(PSO)、遗传算法(GA)…

提取COCO 数据集的部分类

1.python提取COCO数据集中特定的类 安装pycocotools github地址:https://github.com/philferriere/cocoapi pip install githttps://github.com/philferriere/cocoapi.git#subdirectoryPythonAPI若报错,pip install githttps://github.com/philferriere…