volatile,解决内存可见性引起的问题,wait和notify

补充:synchronized(务必会读(辛可肉耐子)会写),要搭配一个对象的时候,不一定非要是访问的this成员

 

synchronized(锁对象){ 代码块}

public synchronized static void func(){} 静态方法和具体对象无关,和类有关了

相当于synchronized(类.class)

在synchronized()里面没有必要去纠结里main写普通对象还是类对象之类的,synchronized不关心对象是什么,只关心两个线程是否针对同一个对象加锁

static:相当于加上了一个类属性/类方法


一、 💛

内存可见性引起的问题,如下图,你在线程1设定假如他不是等于0就终止,然后你在线程2中给他把值改变了,让他的循环结束,但是我么可以看到,当前我们输入了一个不是0的数字,然后试图改变它,却改变不了,这就是内存可见性的问题

程序在运行的时候,java编译器和jvm可能会对代码进行优化,程序猿们写代码,然后java编译器把你代码改了,保持原有逻辑不变的情况下提高代码效率——编译器优化后

并且优化的效果特别好:服务器的启动步骤非常复杂,启动一个差不多10分钟左右(但是假如我们吧优化关了,可能1个小时打底)

我们想要知道他是如何优化的,就要先清楚while循环的本质,两个指令

1.load读取内存

2.jcmp(比较,并且跳转,寄存器操作,速度极快)

此时编译器发现,代码反复的,快速的读取同一个内存值,并且这个内存值每次读出来的结果还是一样的,此时编译器决定,直接把load优化掉了,只是第一次执行load,后续并不执行load,直接拿寄存器中的数据进行比较了。

但是在另一个线程修改t2线程会不会执行,什么时候去执行,因此产生了误判,导致虽然最后t2的isQuit改动了,但是t1线程中,并未重复load也就会导致出现上述问题了。 

import java.util.Scanner;public  class  Demo {public  static int isQuit=0;                 //静态变量public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {           //创立一个线程while(isQuit==0){;}System.out.println("t1 结束了");}); Thread t2 = new Thread(() -> {         //我们去用t2来改变t1的值Scanner scanner=new Scanner(System.in);System.out.println("请输入isQuit的数字");isQuit=scanner.nextInt();    });t1.start();t2.start();}
}

volatile(会读会写 (wao(平🐍)里太哦)弥补上述缺口:意思易变的,修饰一个变量之后,编译器就明白,这个变量是一边倒,就不能按照上述方式处理代码(把读操作优化到寄存器中),让编译器禁止优化,于是保证t1在循环的过程中,始终都能读取内存中的数据

volatile本质是保持变量的内存可见性

见下面代码用法:

下面得到的结果就是正确的,我就暂时省略结果了。

import java.util.Scanner;public  class  Demo {public volatile static int isQuit=0;          //变量static前面public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while(isQuit==0){;}System.out.println("t1 结束了");});Thread t2 = new Thread(() -> {Scanner scanner=new Scanner(System.in);System.out.println("请输入isQuit的数字");isQuit=scanner.nextInt();});t1.start();t2.start();}
}

编译器的优化是一个“玄学问题”,就比如说,我在新代码里面,写了个sleep,同时把volatile取消了,但是这样也正确

可以理解为,加上sleep之后,sleep就会大幅度的影响到while循环的速度,速度慢了,编译器也不打算继续优化了~此时即使不加volatile,也能够及时感知到内存变化了,sleep到底间隔多久,会触发优化,只有那些码届远古大能才知道。 

二、💜 

另一种解释方式

Java的内存模型(JMM)

其实这个理解和上面那个编译器解释原理是一样的,从主内存读,但反复读都是一样的,所以直接就去工作内存读,但是工作内存又是什么鸟东西捏?

工作内存:不是我们平时说的内存,而是cpu的寄存器和cpu缓存统称为工作内存,有人可能会好奇那为啥不叫cpu寄存器+cpu缓存呢(猜:JAVA宣称是跨平台,但是cpu的话又是有一部分硬件知识,他们希望java程序猿可以不用掌握太多的硬件知识。

 内存可见性和加锁描述了线程安全问题的典型情况和处理方式。


三、 💙 

wait(等待)和notify(通知):用来协调线程顺序的重要工具,多线程调度是随机的~很多时候希望多个线程按照咱们规定的顺序来执行,完成线程之间的配合工作。

上面两个都是object提供的方法,也就是说任意对象,当wait引起线程阻塞之后,可以用interrupt方法,把线程给唤醒,打断当前线程的阻塞状态的。

wait执行程序的时候会干三件事:

1.解锁

2.阻塞等待

3.当被其他线程唤醒之后,就会尝试重新加锁,加锁成功,wait执行完毕,继续往下执行其他逻辑。

也就是说wait(需要先加锁)

核心思路:先加锁,在synchronized里面进行wait(加锁要加同一个对象上面),这里的线程会一直阻塞到其他线程notify。

其中最典型的场景就是有效的避免线程饥饿/线程饿汉

 

几个注意

1.要想notify能顺利唤醒wait,就需要确保wait和notify都是同一个对象调用的,

2.wait和notify都需要放到synchronzied之中的,虽然notify不涉及到解锁操作

3.如果进行notify的时候,另一个线程没有处于wait状态,此时notify也没有任何副作用。

t2可以理解成辅助t1的线程,使用notify线程对其他线程统筹安排作用。

import java.util.Scanner;public  class  Demo {public  static Object locker=new Object();public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while(true){synchronized (locker) {System.out.println("t1 开启");       //第一步执行的try {locker.wait();                  //第二步执行,t2陷入阻塞状态} catch (InterruptedException e) {e.printStackTrace();}System.out.println("t1 over");      //第五步,t1被唤醒}}});Thread t2 = new Thread(() -> {while (true) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}synchronized (locker) {System.out.println("t2 开启");      //第三步执行的locker.notify();                   //第四部执行,唤醒t1System.out.println("t2 over");}}});t1.start();t2.start();}
}

 

线程可能有多个~

几个线程wait,一个线程复制notify,notify只会唤醒一个线程,具体哪个随机,notifyAll会唤醒全部线程(但是不推荐去用),这种也是全随机,就和wait的初心违背了。

如果要唤醒某个特定的线程,就要让不同的线程,使用不同的对象来进行wait,想要唤醒谁,就可以使用对应的对象notify

wait和sleep的区别

sleep有明确的使用是假,到达时间自动被唤醒,也能提前用interrupt

wait:死等,一直等到其他线程notify(但是,是正常唤醒,可继续工作,还会进入wait 状态),wait也可以被interrupt提前唤醒(但是这个是来通知线程要结束了,线程要收尾了)

,当然他也有带时间版的和join差不多,因此协调多个线程执行顺序wait比notify更牛一些

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

业务逻辑漏洞之支付逻辑漏洞

业务逻辑漏洞之支付逻辑漏洞 一、漏洞挖掘介绍二、Web漏洞产生的原因三、业务逻辑简述四、 常见业务逻辑漏洞的功能点五、支付逻辑漏洞5.1、漏洞背景5.2、产生原因5.3、测试方法 六、挖到这些漏洞有什么用? 一、漏洞挖掘介绍 漏洞定义: 官方定义&#…

网页版Java(Spring/Spring Boot/Spring MVC)五子棋项目(四)对战模块

网页版Java(Spring/Spring Boot/Spring MVC)五子棋项目(四)对战模块 一、约定前后端交互接口1. 建立连接接口2. 针对落子的请求和响应 二、实现前端页面三、实现后端1. 当用户进入房间,更新用户状态 OnlineUserManager…

ProComponent 用法学习

相信很多同学都用过 Ant Design 这一 react 著名组件库,而 ProComponents 则是在 antd 之上进行封装的页面级组件库(指一个组件就可以搞定一个页面)。它同时也是 Ant Design Pro 中后台框架所用的主要组件库。如果你手上有要用 react 开发的中…

valgrind检测内存泄漏

#include <stdio.h> #include <stdlib.h>int main(){int *q (int *)malloc(sizeof(int));*q 1;// int i 1;// if(i 1){// int *p (int *)malloc(sizeof(int));// *p 1;// free(p);// }// free(q)return 0; } 运行查看 valgrind --leak-checkfu…

【学习】若依源码(前后端分离版)之 “ 上传图片功能实现”

大型纪录片&#xff1a;学习若依源码&#xff08;前后端分离版&#xff09;之 “ 上传图片功能实现” 前言前端部分后端部分结语 前言 图片上传也基本是一个项目的必备功能了&#xff0c;所以今天和大家分享一下我最近在使用若依前后端分离版本时&#xff0c;如何实现图片上传…

虹科新闻 | 虹科与Power-MI正式建立合作伙伴关系

近日&#xff0c;虹科与Power-MI正式建立合作伙伴关系&#xff0c;双方就工业预测性维护领域进行深入的交流与合作&#xff0c;未来将共同致力于为亚洲市场提供完整的、更高质量的预测性维护解决方案&#xff0c;解决亚洲客户的工业自动化挑战。 虹科与Power-MI都表示十分期待…

vite跨域配置踩坑,postman链接后端接口正常,但是前端就是不能正常访问

问题一&#xff1a;怎么都链接不了后端地址 根据以下配置&#xff0c;发现怎么都链接不了后端地址&#xff0c;proxy对了呀。 仔细看&#xff0c;才发现host有问题 // 本地运行配置&#xff0c;及反向代理配置server: {host: 0,0,0,0,port: 80,// cors: true, // 默认启用并允…

接口测试过程中常见的接口安全性问题,通用测试点整理归纳

我们日常的接口测试工作主要是验证接口的功能性&#xff08;入参、出参、边界值等&#xff09;&#xff0c;在接口测试过程中遇到的一些接口安全性的问题&#xff0c;整理成了通用的测试点&#xff0c;不一定适用于全部的产品&#xff0c;仅做参考。 一、登录接口校验 验证登…

Android Framework底层原理之WMS的启动流程

一 概述 今天&#xff0c;我们介绍 WindowManagerService&#xff08;后续简称 WMS&#xff09;的启动流程&#xff0c;WMS 是 Android 系统中&#xff0c;负责窗口显示的的服务。在 Android 中它也起着承上启下的作用。 如下图&#xff0c;就是《深入理解 Android》书籍中的…

编织人工智能:机器学习发展历史与关键技术全解析

文章目录 1. 引言1.1 机器学习的定义1.2 重要性和应用场景重要性应用场景 2. 机器学习的早期历史2.1 初期理论与算法感知机决策树 2.2 早期突破支持向量机神经网络初探 3. 21世纪初期的发展3.1 集成学习方法随机森林XGBoost 3.2 深度学习的崛起卷积神经网络&#xff08;CNN&…

validator入门

validator中文文档地址和英文地址 https://docs.jboss.org/hibernate/validator/4.2/reference/zh-CN/html/validator-gettingstarted.html https://docs.jboss.org/hibernate/validator/6.0/reference/en-US/html_single/#preface自定义hibernate-validator校验 工具类Valid…

电视盒子哪个好?文宇数码盘点口碑网络电视盒子排行榜

大家好&#xff0c;欢迎来到文宇数码频道。本期我们要分享的数码产品是电视盒子&#xff0c;电视盒子可以说是家家必备&#xff0c;很多用户在买电视盒子时踩过雷&#xff0c;因此本期我们的主题是电视盒子哪个好&#xff0c;为了结果更客观公正&#xff0c;我们购入了十多款热…