volatile,wait,notify关键字

news2024/11/30 10:29:30

在这里插入图片描述

文章目录

  • 一、volatile关键字
  • 二、wait 和 notify
    • wait
    • notify
    • notifyAll
    • wait 和 sleep 的区别
    • 顺序打印ABC

一、volatile关键字

volatile关键字的存在是用来解决内存可见性问题的。
在这里插入图片描述
我在 :线程安全问题 这篇文章中介绍过内存可见性问题。
前面我们讨论内存可见性时说了, 直接访问工作内存(实际是 CPU 的寄存器或者 CPU 的缓存), 速度
非常快, 但是可能出现数据不一致的情况.

public class Test {
    static int flg = 0;
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);

        Thread t1 = new Thread(() -> {
            while(flg == 0) {

            }
            System.out.println("t1循环结束");
        });
        Thread t2 = new Thread(() -> {
            System.out.println("输入一个整数");
            flg = scan.nextInt();
        });
        t1.start();
        t2.start();
    }
}

在这里插入图片描述
当我们输入1时,t1线程并没有循环结束,我们可以打开jconsle,观看一下线程信息
在这里插入图片描述
我们可以发现此时t2线程已经执行完成了,但我们的t1仍然在执行。
在这里插入图片描述
我们可以分析一下t1线程所进行的操作,flg == 0需要进行两步操作:

  1. load 把主内存的flg值读取到工作内存
  2. cmp 将工作内存的值与0相比较,决定程序执行。

我们t1线程在t2线程修改flg值之前,load的结果都是一样的,而且load 的 速度与cmp操作相比,速度慢了很多,于是我们JVM就会大胆的认为没人改flg值了,于是不再重复load了。

正是因为这样的误判存在,所以volatile关键字的作用就来了,我们可以给变量flg加上volatile关键字,就是告诉编译器,每次都得load这个变量,可能会发生改变。

在这里插入图片描述
在这里插入图片描述
我们可以发现,当我们加上volatile关键字之后,程序达到了我们预期的效果。
我们上述所看到的内存可见性 编译器优化的问题 是有发生的可能,但也不是百分百出现的。
在这里插入图片描述
在这里插入图片描述
我们在循环的时候,代码稍加改写,加入sleep,让循环执行慢一点,也达到了预期的效果,但这也存在不确定性,最稳妥的做法就是对这些可能存在内存不可见问题的变量加上volatile关键字,volatile保证数据准确的同时,执行速度也会有所下降。
volatile不能保证原子性,原子性靠synchronized保证

二、wait 和 notify

由于线程之间是抢占式执行的, 因此线程之间执行的先后顺序难以预知. 但是实际开发中有时候我们希望合理的协调多个线程之间的执行先后顺序.
我们之前学习的join,sleep也能达到部分的目的,但是join,sleep太过于死板,不够灵活,join必须等t1执行完毕,t2才能执行。sleep必须得指定一个时间,但线程执行的时间我们人为不好估计。
wait 和 notify 可以很好的解决上述问题。
注意: wait, notify, notifyAll 都是 Object 类的方法.

wait

wait使该线程进行阻塞等待
在这里插入图片描述
一样的,我们在使用wait的使用需要抛一个中断异常。

public static void main(String[] args) throws InterruptedException {
        Object o = new Object();
        o.wait();
    }

在这里插入图片描述
我们可以发现报了一个非法锁异常,要想理解这个异常我们需要明白wait所做的事情都是什么:

  1. 释放锁
  2. 进行阻塞等待(等待队列)
  3. 满足条件后,重新尝试获取锁。

现在我们就可以理解这个异常了,我们都没锁,何谈释放锁,就好比我们是单身状态,何谈分手之言。
所以,wait 需要和 synchronized搭配使用的

public static void main(String[] args) throws InterruptedException {
        Object o = new Object();
        synchronized (o) {
            System.out.println("wait前");
            o.wait();
            System.out.println("wait后");
        }
    }

在这里插入图片描述
在这里插入图片描述
怎么唤醒呢?下面我们来了解一下notify关键字

notify

notify 方法用来唤醒wait等待的线程.
该方法同样的,必须在synchronized(obj){}代码块内部使用

public static void main(String[] args) {
        Object o = new Object();
        Thread t1 = new Thread(() -> {
            System.out.println("wait前");
            try {
                synchronized (o) {
                    o.wait();
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        Thread t2 = new Thread(() -> {
            System.out.println("notify之前");
            synchronized (o) {
                o.notify();
            }
            System.out.println("notify之后");
        });
        t1.start();
        t2.start();
    }

在这里插入图片描述
我们使用notify的对象和使用wait的对象必须相同,因为notify只能唤醒同一对象上等待的线程。
在这里插入图片描述
为什么我们这里的结果和我们的预期有些差异
在这里插入图片描述
当我们启动t1,t2线程时,由于线程调度是随机的,不能够保证t1,t2的执行顺序,如果先执行了t2的notify,后执行的t1的wait,此时notify不会起任何意义的,但也对程序没什么坏的影响。
所以我们在使用wait 和 notify一定要保证他们的执行顺序。
在这里插入图片描述
我们可以加一个sleep,让t1线程的wait启动后,再去执行t2现在的notify,当然这个sleep的时间不确定,具体取决于线程调度的时间。
在这里插入图片描述
但要是我们仍害怕notify先执行了,wait就只能死等下去了,那么我们可以wait带参数版本

方法作用
wait()死等
wait(long miles)执行等待最大时间

注意:
1.如果有多个线程等待,则有线程调度器随机挑选出一个呈 wait 状态的线程。(并没有 “先来后到”)
2.在notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行完,也就是退出同步代码块之后才会释放对象锁。

notifyAll

notify方法只是唤醒某一个等待线程. 使用notifyAll方法可以一次唤醒所有的等待线程.
在这里插入图片描述
notify就相当于我们宿舍的卫生间,自己出来之后,随机告诉一个舍友你现在可以去了。
notify 只唤醒等待队列中的一个线程. 其他线程还是处于wait状态
在这里插入图片描述
notifyAll相当于,同时向宿舍的所有舍友喊我出来了,你们可以进去了。
notifyAll 一下全都唤醒, 需要这些线程重新竞争锁

wait 和 sleep 的区别

相同点: sleep()和wait()都可以暂停线程的执行。
不同点:
1.wait是Object的方法,sleep是Thread的静态方法
2. wait 需要搭配 synchronized 使用. sleep 不需要.
3. sleep()方法睡眠指定时间之后,线程会自动苏醒。wait()方法被调用后,可以通过notify()或notifyAll()来唤醒wait的线程。
4. notify唤醒wait是正常的,interrput中断sleep是异常的
5. sleep()常用于一定时间内暂停线程执行,wait()常用于线程间交互和通信。

顺序打印ABC

有三个线程,分别只能打印ABC,三个线程按照ABC的顺序打印。

public static void main(String[] args) throws InterruptedException {
        Object lock1 = new Object();
        Object lock2 = new Object();
        Thread t1 = new Thread(() -> {
            System.out.println("A");
            synchronized (lock1) {
                lock1.notify();
            }
        });
        Thread t2 = new Thread(() -> {
            try {
                synchronized (lock1) {
                    lock1.wait();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("B");
            synchronized (lock2) {
                lock2.notify();
            }
        });
        Thread t3 = new Thread(() -> {
            try {
                synchronized (lock2) {
                    lock2.wait();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("C");
        });
        t2.start();
        t3.start();
        Thread.sleep(100);
        t1.start();
    }

在这里插入图片描述
这里线程启动的顺序为什么是这样,因为我们在t1的notify执行之前,必须保证t2,t3的wait启动。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

教程十 在Go中使用Energy创建跨平台GUI应用 - 事件通信(IPC) 之 Go定义事件JS调用

介绍 Energy Go和JS的事件通信, Go监听事件JS触发。 IPC事件还有其它的几种使用方式,在其它教程中更新 在正常前后端大多数开发场景,JS和Go前后端数据交互都需要Http接口方式交互。 Energy中可以不使用Http,使用事件通信机制(…

使用ProGuard插件对Spring Boot程序进行代码混淆

使用ProGuard插件对Spring Boot程序进行代码混淆 介绍: ​ ProGuard是一个开源的Java类文件(只能处理Java代码,但是对应资源文件等是不能起作用的)的压缩器、优化器、混淆器和预校验器。其处理的过程主要分为以下几个步骤&#…

系统移植总结

1:什么是系统移植 1)系统移植是给开发板搭建一个Linux操作系统 2)从官方获取源码,进行配置和编译,生成板子需要的镜像 2:安装tftp服务器的作用 Tftp服务器:是基于UDP协议完成简单的文件传输 作…

mysql sql优化(索引优化)经验漫谈

文章目录1. 当用sql查找是否“存在”场景2. where 条件 in的限制3. updade语句要不要考虑索引的命中情况4. mysql 预编译 多线程5. 函数与索引失效的关系6. mysql隐性类型转换与索引失效的关系7. 联合索引8. 联合索引最左匹配原则9. 回表 索引覆盖 聚簇索引 非聚簇索引10. 前缀…

这下真的是阳了个阳!

实际情况 很不幸,在前天,出现了新冠阳性的症状,随后用抗原检测了下,有阳的条带出现(很浅,弱阳,因为才出现症状),基本上就是确定阳了。 抗原检测不知道今天是第几天了&…

第40篇 网络(十)WebKit初识

导语 WebKit是一个开源的浏览器引擎。Qt中提供了基于WebKit的QtWebKit模块,它包含了一组相关的类。QtWebKit提供了一个Web浏览器引擎,使用它便可以很容易的将万维网(WorldWide Web)中的内容嵌入到Qt应用程序中。与此同时&#xf…

大二Web课程设计——基于HTML+CSS+JavaScript+jquery手表商城购物网站(17页)

常见网页设计作业题材有 个人、 美食、 公司、 学校、 旅游、 电商、 宠物、 电器、 茶叶、 家居、 酒店、 舞蹈、 动漫、 服装、 体育、 化妆品、 物流、 环保、 书籍、 婚纱、 游戏、 节日、 戒烟、 电影、 摄影、 文化、 家乡、 鲜花、 礼品、 汽车、 其他等网页设计题目, A…

无人机集群的分布式协作 VI-SLAM

以下内容来自从零开始机器人SLAM知识星球 每日更新内容 点击领取学习资料 → 机器人SLAM学习资料大礼包 #论文# D2SLAM: Decentralized and Distributed Collaborative Visual-inertial SLAM System for Aerial Swarm 论文地址:https://arxiv.org/abs/2211.01538…

视频怎么转文字?快把这些方法收好

如今短视频让知识传播变得越来越简单,我们可以很轻松的就通过短视频了解到大量的知识要点。但是当我们想要回温知识点的时候,需要重新观看视频,这就有些不太便利。其实我们可以通过将视频转成文字,这样子就容易归纳知识点了。那你…

Jlink commander使用方法(附指令大全)

Jlinkcmd它可以方便用户在非仿真的情况下,hold内核、单步、全速、设置断点、查看内核和外设寄存器、读取flash代码等等,方便大家拥有最高的权限查看在运行中的MCU情况,查找非IDE仿真情况下,MCU运行异常的原因。 目录 驱动安装 …

粉笔科技张小龙:能传授知识文化和技能,就是对社会的贡献和交代

粉笔科技张小龙在一次粉笔科技的管培生大会上强调,今天是互联网时代,你只有为别人提供价值,提供更高品质的价值,以及更高效率的提供价值,你才有价值。一个企业是这样,一个人也是这样。#张小龙# 你把事情做到…

微服务框架 SpringCloud微服务架构 分布式缓存 42 Redis 主从 42.4 数据同步原理【优化】

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式,系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 分布式缓存 文章目录微服务框架分布式缓存42 Redis 主从42.4 数据同步原理【优化】42.4.1 主从同步的问题优化42.4.2 总结42 Redis 主从 42…

QA | SWCF2022 笔记:C波段卫星与5G之间的干扰排查及解决方案

2022年度SWCF卫星通信与仿真测试研讨会正在进行中。昨日精彩演讲:C波段卫星与5G之间的干扰排查及解决方案,昨晚收到一些粉丝的技术问题,我们汇总了热点问题并请讲师详细解答。 演讲主题:C波段卫星与5G之间的干扰排查及解决方案 干…

龙芯内核的UOS安装 Mariadb-server

1.安装 Mariadb-server 1.1安装配置 sudo apt install mariadb-server启动数据库 systemctl start mariadb;设置数据库自启动 systemctl enable mariadb;对数据库进行一些设置 mysql_secure_installation输入当前密码(因为是第一次安装,没有密码&am…

基于Android的应用市场软件的设计

基于Android的应用市场软件的设计 摘  要 随着智能手机的普及,人们越来越依赖手机进行一系列操作。 由于Android系统是一款免费的操作系统,导致了使用Android系统的手机占到7成左右。为了让Android手机用户体验更好,就需要让Android手机用…

【linux】之私有云OpenStack手动分布式部署

一、环境准备 参考: https://docs.openstack.org/zh_CN/install-guide/ 1, 静态IP(NetworkManager服务可以关闭) 2,主机名与绑定 192.168.122.11 controller 192.168.122.12 compute 192.168.122.13 cinder3, 关闭防火墙和selinux 4, 时间同步 所有节点准备yum源 # yum …

12.6、后渗透测试--Windows系统下信息收集模块

一、存活主机发现 步骤1、使用arp查看缓冲表:meterpreter > arp步骤2、局域网内存活主机发现:meterpreter > run post/windows/gather/arp_scanner RHOSTS172.16.0.0/24二、应用程序枚举 方法1: 获取靶机上的软件安装信息meterpreter…

免费刷题的软件测试面试题库小程序,萌新必备

现如今,不仅学习卷、考证卷,就连找工作也开始卷得没边了。就如最近几年新崛起的软件测试岗位,很多人为了能过快速通过面试,或者拿到offer,纷纷在面试前几周左右,不惜花重金,购买面试题目&#x…

【总结】有三AI所有原创GAN相关的学习资料汇总(2022年12月)

GAN的研究和应用在这几年发展可以说是非常迅猛,无疑是这几年深度学习计算机视觉领域里落地性最酷的技术之一,包括图像与视频生成,数据仿真与增强,各种各样的图像风格化任务,人脸与人体图像编辑,图像质量提升…

高分子PEGDBCO-PEG-Acrylates,DBCO-PEG-ACRL,二苯并环辛炔PEG丙烯酸酯

●外观以及性质: DBCO-PEG-ACRL产物呈固体或粘性液体,取决于PEG分子量“点击化学"一般由叠氮化物(azide)和炔烃(alkyne)作用形共价键,具有高效稳定,高特异性等优点。反应不受PH…