并发编程之的虚假唤醒和精准唤醒的详细解析

虚假唤醒

例子

wait()是object类自带的方法,在jdk有介绍,有可能出现中断、虚假唤醒

也就是在下面的例子中

if(number != 0){
 this.wait();
}

当线程成功进入if语句块中,发生了中断,cpu跑去调度别的进程了,再次调度这个线程的时候,应该需要再经历一次if的判断,但是并没有这样做。

于是下面的程序运行结果:

/**
 * @author zkw
 * @Description TODO
 * 
 */
public class ThreadWaitNotify {
    public static void main(String[] args) {
        Resource resource = new Resource();
        //increment
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    resource.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A-1").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    resource.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A-2").start();
​
        //decrement
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    resource.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B-1").start();
        new Thread(()->{
            try {
                resource.decrement();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"B-2").start();
    }
​
}
​
class Resource{
    private int number = 0;
​
    //number++
    public synchronized void increment() throws InterruptedException {
        if(number != 0){
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName()+":"+number);
        this.notifyAll();
    }
    //number--
    public synchronized void decrement() throws InterruptedException {
        if(number == 0){
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+":"+number);
        this.notifyAll();
    }
​
​
}

解决办法

按照jdk文档的指示,应该将if换成while

      
  while(number == 0){
            this.wait();
        }

修改后,正确的运行结果如下:

精准唤醒

JUC那套 lock、await、signal和 Object那套 synchronized、wait、notify的区别:

condition这一套能实现精确唤醒某一个线程,而不是像notifyAll那样唤醒全部线程。

下面这个例子中,一共创建了三个Condition,可以根据业务对这三个Condition依次唤醒。来达到精准唤醒的功能

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
​
/**
 * @author zkw
 * @Description 线程顺序访问
 *  多线程之间的顺序调用  A-》B-》C
 *  三个线程启动,要求如下:
 *  AA打印5次,BB打印10次,CC打印15次
 *  接着
 *  AA打印5次,BB打印10次,CC打印15次
 *  ....来10轮
 *
 *  1 高内聚低耦合的前提下,线程 操作 资源类
 *  2 判断/干活/通知
 *  3 多线程交互中,必须要防止多线程的虚假唤醒,也即(判断只用while不用if)
 *  4 标志位
 * 
 */
public class ThreadOrderAccess {
    public static void main(String[] args) {
        ShareResource shareResource = new ShareResource();
        new Thread(()->{
            try {
                for (int i = 0; i < 10; i++) {
                    shareResource.printf5();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"Thread1").start();
        new Thread(()->{
            try {
                for (int i = 0; i < 10; i++) {
                    shareResource.printf10();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"Thread2").start();
        new Thread(()->{
            try {
                for (int i = 0; i < 10; i++) {
                    shareResource.printf15();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"Thread3").start();
    }
}
​
class ShareResource{
    private int number = 1; //1:A    2:B    3C
    private Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();
    public void printf5() throws InterruptedException {
        lock.lock();
        try {
            while (number!=1){
                condition1.await();
            }
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName()+"--AA");
            }
            number = 2;
            condition2.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
​
    public void printf10() throws InterruptedException {
        lock.lock();
        try {
            while (number!=2){
                condition2.await();
            }
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName()+"--BB");
            }
            number = 3;
            condition3.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
​
    public void printf15() throws InterruptedException {
        lock.lock();
        try {
            while (number!=3){
                condition3.await();
            }
            for (int i = 0; i < 15; i++) {
                System.out.println(Thread.currentThread().getName()+"--CC");
            }
            number = 1;
            condition1.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
​

 

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

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

相关文章

厨余垃圾处理设备工业监控PLC连接APP小程序智能软硬件开发之功能结构篇

厨余垃圾处理设备工业监控PLC连接APP小程序智能软硬件开发之功能结构篇 好几年前&#xff0c;应朋友之邀&#xff0c;为其工厂的厨余垃圾处理设备研发一套用于对现场的生产及维护进行远程查看、管理和质量监控的厨余垃圾处理设备工业监控PLC连接APP小程序智能软硬件系统。 因为…

MVC框架里的几种对象

Java语言是一门面向对象的编程语言&#xff0c;所有都用类表达&#xff0c;入口都是一个类&#xff0c;没有独立的main&#xff08;&#xff09;函数&#xff0c;类的实例化就是对象。 简单来讲类包括数据和方法&#xff0c;方法就是操作&#xff0c;是实现业务逻辑的地方&…

获取高德安全码SHA1

高德开发者平台上给的三种方法 获取安全码SHA1&#xff0c;这里我自己使用的是第三种方法。 1、通过Eclipse编译器获取SHA1 使用 adt 22 以上版本&#xff0c;可以在 eclipse 中直接查看。 Windows&#xff1a;依次在 eclipse 中打开 Window -> Preferances -> Androi…

C++动态内存管理:new/delete与malloc/free的对比

在C中&#xff0c;动态内存管理是一个至关重要的概念。它允许我们在程序运行时根据需要动态地分配和释放内存&#xff0c;为对象创建和销毁提供了灵活性。在C中&#xff0c;我们通常会用到两对工具&#xff1a;new/delete 和 malloc/free。虽然它们都能够完成类似的任务&#x…

「10」文本(GDI+):添加文字,可设置背景添加移动效果

「10」文本&#xff08;GDI&#xff09;添加文字&#xff0c;可设置背景添加移动效果 在OBS软件里&#xff0c;通过来源组件「文本&#xff08;GDI&#xff09;」&#xff0c;您可以添加任意您想要呈现的文字&#xff0c;在直播窗口中显示&#xff0c;它可以是提示语、广告词、…

【双指针】Leetcode 盛最多水的容器

题目解析 11. 盛水最多的容器 木桶效应&#xff0c;寻找一个区间使得这个区间的体积最大 算法讲解 1. 暴力枚举 遍历这个容器&#xff0c;将每一个区间的体积求出来&#xff0c;然后找出最大的 class Solution { public:int maxArea(vector<int>& height){int n…

【技术总结】常用指标mAP, mIoU, mDice, mFscore, aAcc 实现

mAP mAP 全称是 mean Average Precision. 其中 mean 这个操作是在 class 级别上, 因此只需要将所有类别平均即可. 所有需要关注的就是 AP. AP 是 Precision-Recall 曲线和坐标轴围成的面积. 提到曲线可能会感觉比较懵 – 模型的预测对或者不对都是确定的, 哪里来的曲线呢? 想…

字节算法岗二面,凉凉。。。

节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学&#xff0c;针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 汇总…

php反序列化刷题1

[SWPUCTF 2021 新生赛]ez_unserialize 查看源代码想到robots协议 看这个代码比较简单 直接让adminadmin passwdctf就行了 poc <?php class wllm {public $admin;public $passwd; }$p new wllm(); $p->admin "admin"; $p->passwd "ctf"; ec…

【第三方登录】Google邮箱

登录谷歌邮箱开发者 https://console.developers.google.com/ 先创建项目 我们用的web应用 设置回调 核心主要&#xff1a; 1.创建应用 2.创建客户端ID 3.设置域名和重定向URL 4.对外公开&#xff0c;这样所有的gmail邮箱 都能参与测试PHP代码实现 引入第三方包 h…

【云能耗管理系统在某大型商场的应用】安科瑞Acrel-EIOT能源物联网平台方案

摘要&#xff1a;依据对上海市某大型商场现场考察的结果&#xff0c;提出通过建设云能耗管理系统的方案来改善商场能耗的管理现状。首先充分搜集建筑信息和设备运行工况&#xff0c;合理设计系统实施方案&#xff0c;解决现场数据采集和传输障碍&#xff0c;完成云能耗管理系统…

常用设计模式介绍

前言 简说设计模式。 文章目录 前言一、设计模式的要素1、设计模式解决的问题2、设计模式分类1&#xff09;创建型设计模式2&#xff09;结构型设计模式3&#xff09;行为型设计模式 二、详细介绍1、创建型设计模式1&#xff09;工厂方法模式2&#xff09;抽象工厂模式3&#x…

【JavaEE】进程是什么?

文章目录 ✍进程的概念✍进程存在的意义✍进程在计算机中的存在形式✍进程调度 ✍进程的概念 每个应⽤程序运⾏于现代操作系统之上时&#xff0c;操作系统会提供⼀种抽象&#xff0c;好像系统上只有这个程序在运⾏&#xff0c;所有的硬件资源都被这个程序在使⽤。这种假象是通…

上位机图像处理和嵌入式模块部署(qmacvisual拟合圆和拟合椭圆)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们学习了拟合直线&#xff0c;今天继续学习下拟合圆和拟合椭圆。其实除了最后一步不同&#xff0c;两者的逻辑是差不多的。一般都是&#xf…

C语言例4-6:格式字符d的使用例子

代码如下&#xff1a; //格式字符d的使用例子 #include<stdio.h> int main(void) {int num1123;long num2123456;printf("num1%d,num1%5d,num1%-5d,num1%2d\n",num1,num1,num1,num1);//以四种不同格式&#xff0c;输出int型数据num1的值printf("num2%ld,…

Elasticsearch 索引模板、生命周期策略、节点角色

简介 索引模板可以帮助简化创建和二次配置索引的过程&#xff0c;让我们更高效地管理索引的配置和映射。 索引生命周期策略是一项有意义的功能。它通常用于管理索引和分片的热&#xff08;hot&#xff09;、温&#xff08;warm&#xff09;和冷&#xff08;cold&#xff09;数…

【研发管理】产品经理知识体系-战略

导读&#xff1a;了解和掌握产品经理知识体系-战略是产品经理必修课。战略在产品创新管理框架中核心位置。本文概要梳理战略相关知识内容&#xff0c;仅供大家参考。 目录 1、战略定义 1.1 战略金字塔 1.2 战略的层级总表 1.3 战略跟战术的关系 1.4 愿景、使命和价值观​编…

ExoPlayer架构详解与源码分析(12)——Cache

系列文章目录 ExoPlayer架构详解与源码分析&#xff08;1&#xff09;——前言 ExoPlayer架构详解与源码分析&#xff08;2&#xff09;——Player ExoPlayer架构详解与源码分析&#xff08;3&#xff09;——Timeline ExoPlayer架构详解与源码分析&#xff08;4&#xff09;—…

yolov8直接调用zed相机实现三维测距(python)

yolov8直接调用zed相机实现三维测距&#xff08;python&#xff09; 1. 相关配置2. 相关代码3. 实验结果 相关链接 此项目直接调用zed相机实现三维测距&#xff0c;无需标定&#xff0c;相关内容如下&#xff1a; 1.yolov5直接调用zed相机实现三维测距&#xff08;python&#…

2024年哈尔滨工业大学材料科学与工程学院硕士研究生招生复试名单

2024年哈尔滨工业大学材料科学与工程学院硕士研究生招生复试名单 材料科学与工程学院2024年硕士研究生招生考试复试及录取工作方案 &#xff08;含深圳、威海校区&#xff0c;不含航天学院复合材料方向&#xff09; 复试录取名单数据分析: {51412, 50222, 50242, 61121, 50251…