当前位置: 首页 > news >正文

深入Volatile

深入Volatile

1、变量不可见性:

1.1多线程下变量的不可见性

直接上代码

/*** @author yourkin666* @date 2024/08/12/16:12* @description*/
public class h1 {public static void main(String[] args) {MyClass myClass = new MyClass();myClass.start();while (true) {if (myClass.isFlag()) {System.out.println("circle!!!");}}}}
class MyClass extends Thread{private boolean flag = false;@Overridepublic void run() {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}flag = true;System.out.println("flag = "+ flag);}public boolean isFlag() {return flag;}public void setFlag(boolean flag) {this.flag = flag;}
}

子线程从主内存中读取数据放到工作内存,将flag修改为true,但是此时flag的值还没有写回主内存,所以主线程读取的flag依然是false

当子线程将flag值写回主内存后,main函数里面的while(true)调用的是系统比较底层的代码,速度较快,没时间再去主存中读取flag

所以while(true)读取到的值一直是false(当然主线程可能在一个时刻去主内存读取最新的值,我们无法控制)

1.2变量不可见性内存语义

JMM(java内存模型)是针对于Java并发编程的模型

JMM规范

  • 所有共享变量(实例变量和类变量)都存在于主内存,不包含局部变量,因为局部变量是线程私有
  • 每一个线程都还有自己的工作内存,在工作内存中,保存了一份共享变量的副本
  • 线程对变量的所有操作都在工作内存中完成
  • 不同线程的工作内存是隔离的

可见性问题的原因

  • 所有共享变量都存在于主内存,每个线程都有自己的工作内存,而且线程读写共享数据也是通过本地内存交换的,所以导致了可见性问题
1.3变量不可见行的解决方案

​ 第一种是加锁

​ 第二种是使用volatile关键字

加锁:

while (true) {synchronized (myClass) {if (myClass.isFlag()) {System.out.println("circle!!!");}}
}

线程进入synchronized代码块前后的执行过程:

  1. 线程获得锁
  2. 清空工作内存
  3. 从主内存拷贝共享变量的最新值
  4. 执行代码块
  5. 将修改后的副本的值刷新回主内存中
  6. 线程释放锁

volatile关键字:

    private volatile boolean flag = false;

工作原理:

  1. 子线程从主内存读取数据放在工作内存,修改flag值后,还没有写回主内存
  2. 此时主线程读取到了flag值为false
  3. 当子线程将flag写回主线程后,就失效工作内存中的拷贝值
  4. 再次对flag进行操作时,线程会从主内存读取最新值,放入工作内存

volatile关键字保证不同线程对共享变量操作的可见性,也就是一个线程修改了volatile修饰的变量,当此变量写回主内存,其他线程可以立即看到最新值

volatile修饰的变量可以在多线程并发修改下,实现线程间变量的可见性

2、volatile其他特性:

1.volatile不保证原子性
/*** @author yourkin666* @date 2024/08/12/16:12* @description*/
public class h1 {public static void main(String[] args) {Runnable myClass = new MyClass();for (int i = 1; i <= 100 ; i++) {new Thread(myClass).start();}}
}
class MyClass implements Runnable{private volatile int count = 0;@Overridepublic void run() {for (int i = 1; i <= 10000; i++) {count++;System.out.println("count >>>>" + count);}}
}

count++是非原子操作,起码可以被分为三步

在多线程环境下,volatile修饰的变量也是线程不安全的

要保证数据的安全性,还得是,或者原子类

原子类:

​ java.util.concurrent.atomic(Atomic包)

​ 这个包中的原子操作类提供一种用法简单、性能高效、 线程安全地更新一个变量的方式

AtomicInteger:

原子型Integer ,可以实现原子更新操作:

public AtomicInter()
初始化一个默认值为0的原子型Integet    
public AtomicInter(int initialValue)
初始化一个指定值的原子型Integet
int get()
获取值    
int getAndIncrement() 
以原子方式将当前值加1,返回自增前的值
int incrementAndget() 
以原子方式将当前值加1,返回自增后的值
int addAndGet(int data)
以原子方式将输入的值与AtomicInteger里的value相加,并返回结果
int getAndSet(int value)
以原子方式设置newValue的值,并返回旧值             
2.禁止指令重排序

为了提升程序的运行效率,编译器和处理器常常对指令进行重排序

使用volatile可以禁止指令重排序,从而修正重排序可能带来的并发安全问题

3、volatile内存语义:

volatile写读建立的happens - before关系:

从JDK5开始,提出happens - before概念,来阐述操作之间的内存可见性。

如果一个操作的结果需要对另一个操作可见,那么这两个操作之间必须存在happens - before关系。(这里提到的两个操作既可以是在一个线程中,也可以是不同线程之间

happens - before规则:
  • 单线程规则

    同一个线程中,前面的所有写操作对后面的操作可见

  • 锁规则(synchronized、Lock等)

    如果线程1解锁了monitor A ,接着线程2锁定了A,那么,线程1解锁A之前的写操作都对线程2可见

  • volatile变量规则

    如果线程1写入volatile变量v(临界资源),接着线程2读取了v,那么,线程1写入v及之前的写操作都是对线程2可见的

  • 传递性

    A对B可见,B对C可见,那么A对C可见

  • start()规则

    假设线程A在执行过程中,通过执行ThreadB.start()来启动线程B,那么线程A在线程B执行前对共享变量的修改,是对线程B可见(线程B启动后的,线程A对变量的修改,线程B就未必看得到了

  • join()规则

    线程t1写入的所有变量,在任意其他线程t2调用t1.join(),或者t1.isAlive()成功返回后,都对t2可见

4、volatile相关面试题:

相关文章:

深入Volatile

深入Volatile 1、变量不可见性&#xff1a; 1.1多线程下变量的不可见性 直接上代码 /*** author yourkin666* date 2024/08/12/16:12* description*/ public class h1 {public static void main(String[] args) {MyClass myClass new MyClass();myClass.start();while (tr…...

数据结构 ——— 顺序表oj题:编写函数,合并两个有序数组

目录 题目要求 代码实现 题目要求 nums1 和 nums2 是两个升序的整型数组&#xff0c;另外有两个整数 m 和 n 分别代表 nums1 和 nums2 中的元素个数 要求合并 nusm2 到nums1 中&#xff0c;使合并后的 nums1 同样按升序顺序排列 最终&#xff0c;合并后的数组不应由函数返…...

Proto文件相关知识

百度Apollo的数据结构常用proto文件来定义&#xff0c; proto文件允许你以类似于C结构体或类的方式定义数据结构。你可以在这个文件中定义简单数据类型、枚举、消息类型等。 基于proto文件&#xff0c;Protocol Buffers编译器&#xff08;protoc&#xff09;可以自动生成对应的…...

k8s的控制节点不能访问node节点容器的ip地址

master控制node服务器添加容器后,访问不了该node服务器容器的ip,只能在node服务器访问 排查后发现是k8s的master服务器和node节点的网址网段和k8s初始化时提示的ip网段不一致 我之前是192.168.137.50, 实际上master主机期望的是192.168.1.50 解决方案: 1.删除服务器后重建ma…...

鸿蒙OpenHarmony

开源鸿蒙系统编译指南 Ubuntu编译环境配置第一步&#xff1a;Shell 改 Bash第二步&#xff1a;安装Git和安装pip3工具第三步&#xff1a;远程仓配置第四步&#xff1a;拉取代码第五步&#xff1a;安装编译环境第六步&#xff1a;本地编译源码 Windows开发环境配置第一步&#x…...

把白底照片变蓝色用什么软件免费 批量更换证件照底色怎么弄

作为专业的修图师&#xff0c;有时候也会接手证件照修图和换底色工作&#xff0c;这种情况下&#xff0c;需要换底色的照片也许达到上百张。为了提高工作效率&#xff0c;一般需要批量快速修图&#xff0c;那么使用什么软件工具能够给各式不同的照片批量更换背景色呢&#xff1…...

Spring之生成Bean

Bean的生命周期&#xff1a;实例化->属性填充->初始化->销毁 核心入口方法&#xff1a;finishBeanFactoryInitialization-->preInstantiateSingletons DefaultListableBeanFactory#preInstantiateSingletons用于实例化非懒加载的bean。 1.preInstantiateSinglet…...

笔记整理—linux进程部分(6)进程间通信、alarm和pause

两个进程间通信可能是任何两个进程间的通信&#xff08;IPC&#xff09;。同一个进程是在同一块地址空间中的&#xff0c;在不同的函数与文件以变量进程传递&#xff0c;也可通过形参传递。2个不同进程处于不同的地址空间&#xff0c;要互相通信有难度&#xff08;内存隔离的原…...

Java网络通信—UDP

0.小记 1.udp通信不需要建立socket管道&#xff0c;一边只管发&#xff0c;一边只管收 2.客户端&#xff1a;将数据&#xff08;byte&#xff09;打包成包裹&#xff08;DatagramPacket&#xff09;&#xff0c;写上地址&#xff08;IP端口&#xff09;&#xff0c;通过快递站&…...

k8s架构,从clusterIP到光电半导体,再从clusterIP到企业管理

clusterIP作为k8s中的服务&#xff0c; 也是其他三个服务的基础 ~]$ kubectl create service clusterip externalname loadbalancer nodeport 客户端的流量到service service分发给pod&#xff0c;pod由控制器自动部署&#xff0c;自动维护 那么问题是service的可用…...

vue框架和uniapp框架区别

文章目录 vue框架和uniapp框架区别一、引言二、Vue.js 概述1、Vue.js 简介1.1、特点 2、适用场景 三、Uni-app 概述1、Uni-app 简介1.1、特点 2、适用场景 四、区别与比较1、跨平台能力2、开发体验3、性能优化4、社区和支持 五、总结 vue框架和uniapp框架区别 一、引言 在前端…...

828华为云征文 | 华为云Flexus云服务器X实例搭建Zabbix网络设备监视系统(Ubuntu服务器运维)

前言 Flexus X实例内嵌智能应用调优算法&#xff0c;性能强悍&#xff0c;基础模式GeekBench单核及多核跑分可达同规格独享型实例的1.6倍&#xff0c;性能模式更是超越多系列旗舰型云主机&#xff0c;为企业业务提供强劲动力。 &#x1f4bc; Flexus X Zabbix&#xff1a;打造…...

JAVA基础-线程(Thread)、多线程(Multi-threaded)

1、知识铺垫 要想了解什么是线程&#xff0c;首先要搞明白线程与进程的区别&#xff0c;并行与并发的区别 1.1 线程与进程 进程&#xff1a;是指⼀个内存中运⾏的应⽤程序&#xff0c;每个进程都有⼀个独⽴的内存空间&#xff0c;⼀个应⽤程序可以同时运⾏多个进程&#xff1b…...

hystrix微服务部署

目录 一.启动nacos和redis 1.查看是否有nacos和redis 二.开始项目 1.hystrix1工程&#xff08;修改一下工程的注册名字&#xff09; 2.运行登录nacos网站查看运行效果&#xff08;默认密码nacos,nacos&#xff09; 3.开启第二个项目 hystrix2工程 4.关闭第二个项目 hyst…...

使用百度文心智能体创建多风格表情包设计助手

文章目录 一、智能定制&#xff0c;个性飞扬二、多元风格&#xff0c;创意无限 百度文心智能体平台为你开启。百度文心智能体平台&#xff0c;创建属于自己的智能体应用。百度文心智能体平台是百度旗下的智能AI平台&#xff0c;集成了先进的自然语言处理技术和人工智能技术&…...

【嵌入式裸机开发】智能家居入门3(MQTT服务器、MQTT协议、微信小程序、STM32)

前面已经写了两篇博客关于智能家居的&#xff0c;服务器全都是使用ONENET中国移动&#xff0c;他最大的优点就是作为数据收发的中转站是免费的。本篇使用专门适配MQTT协议的MQTT服务器&#xff0c;有公用的&#xff0c;也可以自己搭建 前言一、项目总览二、总体流程分析1、了解…...

css的背景background属性

CSS的background属性是一个简写属性&#xff0c;它允许你同时设置元素的多个背景相关的子属性。使用这个属性可以简化代码&#xff0c;使其更加清晰和易于维护。background属性可以设置不同的子属性。 background子属性 定义背景颜色 使用background-color属性 格式&#x…...

Cypress自动化测试实战:构建高效的前端测试体系

在快速迭代的软件开发环境中&#xff0c;前端自动化测试是保证代码质量和用户体验的重要手段。Cypress作为一款功能强大的前端自动化测试工具&#xff0c;凭借其丰富的特性、直观的API和高效的测试执行速度&#xff0c;赢得了众多开发者和测试团队的青睐。本文将深入探讨Cypres…...

【YOLO学习】YOLOv2详解

文章目录 1. 概述2. Better2.1 Batch Normalization&#xff08;批归一化&#xff09;2.2 High Resolution Classifier&#xff08;高分辨率分类器&#xff09;2.3 Convolutional With Anchor Boxes&#xff08;带有Anchor Boxes的卷积&#xff09;2.4 Dimension Clusters&…...

windows 录音编码为flv格式时,pcm采样格式

这里使用的是0x3e&#xff0c;转换为二进制&#xff1a; 0 0 1 1 1 1 1 0 前四个字节为3&#xff0c;表示Linear Pcm, 后4个字节1 1 1 0 表示44100HZ采样&#xff0c; 16个bit&#xff0c;单声道。 故&#xff0c;windows 音频采样不支持48000HZ频率...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

MFC 抛体运动模拟:常见问题解决与界面美化

在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...