JUC并发编程——Volatile详解(基于狂神说的学习笔记)

Volatile

Volatile 是Java虚拟机提供的轻量级的同步机制

1、保证可见性

public class JMMDemo {// 在num前添加关键字volatile,保证num在所有线程可见,即修改就被通知private volatile static int num = 0;public static void main(String[] args) throws InterruptedException {// 主线程new Thread(()->{// 线程1while(num == 0){}}).start();TimeUnit.SECONDS.sleep(1);num = 1;System.out.println(num);}
}

2、不保证原子性

原子性:不可分割的操作

线程A在执行任务的时候,不能被打扰,也不能被分割,要么同时成功,要么同时失败

package Volatile;// 验证 volatile不保证原子性
public class vDemo02 {private volatile static int num = 0;public static void add(){num++;}public static void main(String[] args) {for (int i = 1; i <= 20; i++) {new Thread(()->{for (int j  = 0; j < 1000; j++) {add();}}).start();}while(Thread.activeCount()>2){Thread.yield();}System.out.println(Thread.currentThread().getName()+" "+num);}
}

以上示例可以说明volatile不保证原子性

我们已经将num声明为volatile,运行结果之后可以发现,num依然小于20000

或许会有笔者忘记了为什么num会小于20000,又为什么小于20000会表明程序没有原子性,我们再来回顾一下,没有忘记的读者可以跳过该部分。

首先,读者需要知道的是,在底层,num++其实并不是一条指令,而是三条指令(感兴趣的小伙伴看图解操作系统),第一步,从内存中读取num的值放到寄存器中,第二步,对寄存器内的值进行+1运算,第三步,将寄存器的值放回到num的地址中。

该实例开启了20条线程。20条线程都在执行同样的操作,即调用add方法1000次,总过加起来有20个1000。而因为线程之间会相互抢占CPU资源,在没有锁(synchronized、lock等)的情况下,会出现以下情况:

此时num=50,线程A进入add方法,将num++;即num=51

但线程A还未写入内存时,便被线程B抢了CPU资源

因为A没有将51写入内存,B看到的num依旧是50,此时他对num++;然后写入内存

然后A又抢到CPU资源,因为A之前的操作停留在num++上,也就是说,它的下一步是将num写入内存(机器很傻,它不会察觉自己手上的num已经发生改变,而是遵循着代码的顺序,执行下一条指令,而num++后的下一条指令为“把num写入内存”)它将自己手上的num,也就是51,又写进内存

因此,A线程与B线程进行了两次num++操作,理应num应该从50变到52,结果只是从50变成51,而在程序中,这种情况可能出现,也可能不会出现,可能在任何时候出现,因此无法预测,每一次运行都是一个全新的结果。

现在理解为何示例不保证原子性了吧,因为它并没有遵循“线程在执行任务的时候不可被打扰,其操作要么全部成功,要么全部失败”,很显然,A线程在执行任务的时候被中断了,num++成功,但写入内存失败。

如何保证线程具有原子性呢?

很简单,使用lock或synchronized锁就好了

但如果不见lock或synchronized锁,怎样保证原子性呢?

使用Atomic**

如:num为integer类型,则使用AtomicInteger

// 验证 volatile不保证原子性
public class vDemo02 {// 不保证原子性//private volatile static int num = 0;// 原子性操作private static AtomicInteger num = new AtomicInteger();public static void add(){// num++;num.getAndIncrement(); // CAS计算机底层并发原理,效率极高!!}public static void main(String[] args) {for (int i = 1; i <= 20; i++) {new Thread(()->{for (int j  = 0; j < 1000; j++) {add();}}).start();}while(Thread.activeCount()>2){Thread.yield();}System.out.println(Thread.currentThread().getName()+" "+num);}
}

这些类的底层都是直接与操作系统挂钩,在内存中修改值

3、禁止指令重排

什么是指令重排

你写的程序,计算机并不是按照你写的那样去执行的

源代码=>编译器优化的重排=>指令并行也可能会重排=>内存系统也会重排=>执行

处理器在执行指令重排的时候,会考虑数据之间的依赖性,意图保证程序不出错

但在并发情况下,这种重排可能会产生错误

例如:

a,b,c,d四个值默认都是0

以下是我们开了两个线程,代码顺序为自上往下

线程A线程B
x=ay=b
b=1a=2

正常结果:x=0 y=0

但实际上指令重排后可能会产生如下顺序:

线程A线程B
b=1a=2
x=ay=b

指令重排导致的结果为:x=2 y=1

volatile可以避免指令重排

volatile可以生成内存屏障,内存屏障为CPU指令,作用:

1、保证特定的操作的执行顺序

2、保证某些变量的内存可见性

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

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

相关文章

数字电路学习

资料 元器件 电流、电压、电阻、电容、电感、保险丝、熔断器、接插件、蜂鸣器、继电器、三极管、mos管、 型号、特性、参数 数据手册 立创商城&#xff1a;https://www.szlcsc.com/?cZH 华秋商城&#xff1a;https://www.hqchip.com/ 公式 欧姆定律 IU/R 仿真软件 mu…

Crypto(5)2023xctf ezCrypto(待补)

下载地址&#xff1a; https://adworld.xctf.org.cn/match/list?event_hasha37c4ee0-1808-11ee-ab28-000c29bc20bf 题目代码分析&#xff1a; #这两行导入了Python标准库中的 random 和 string 模块&#xff0c;用于生成随机数和处理字符串 import random import stringcha…

【六:pytest框架介绍】

常见的请求对象requests.get()requests.post()requests.delete()requests.put()requests.request()常见的响应对象reprequests.request()//返回字符串格式数据print(req.text)//返回字节格式数据print(req.content)//返回字典格式数据print(req.json)#状态码print(req.status_c…

LLMs之RAG:利用langchain实现RAG应用五大思路步骤—基于langchain使用LLMs(ChatGPT)构建一个问题回答文档的应用程序实战代码

LLMs之RAG:利用langchain实现RAG应用五大思路步骤—基于langchain使用LLMs(ChatGPT)构建一个问题回答文档的应用程序实战代码 目录 相关文章

基于STM32设计的小龙虾养殖系统(带手机APP)

一、项目介绍 随着人们对健康生活需求的提高,小龙虾逐渐成为现代消费者餐桌上的一道风味佳肴,并且市场需求不断扩大。然而,小龙虾的养殖需要注意许多因素,其中最重要的就是水质条件。水质不良会导致小龙虾死亡率增加,降低养殖效益。因此,为了保证小龙虾的健康生长,必须…

神经网络的发展历史

神经网络的发展历史可以追溯到上世纪的数学理论和生物学研究。以下是神经网络发展史的详细概述&#xff1a; 早期的神经元模型&#xff1a; 1943年&#xff0c;Warren McCulloch和Walter Pitts提出了一种神经元模型&#xff0c;被称为MCP神经元模型&#xff0c;它模拟了生物神经…

v-model修饰符 .lazy .number .trim

1、v-model.lazy“xxx” 默认情况下&#xff0c;v-model它是在每次输入数据时触发input事件来更新数据的 使用 .lazy 修饰符后&#xff0c;当改变数据失去焦点-触发change事件来进行更新数据 2、v-model.number"xxx" 它会自动将输入的值自动转成number 类型&#x…

使用高防服务器有什么好处?103.216.155.x

为什么建议租用高防服务器 第一&#xff0c;高防服务器由于业务的特殊性&#xff0c;本身机器的配置要求高&#xff0c;服务器的价格相比普通的贵&#xff0c;而且&#xff0c;机器还有维护费、托管费等&#xff0c;这会让运营的成本上升。 第二&#xff0c;租用高防服务器&a…

GC overhead limit exceeded问题

1.问题现象 程序包运行时候发生了java.lang.OutOfMemoryError: GC overhead limit exceeded异常&#xff0c; 详细信息如下 org.apache.ibatis.exceptions.PersistenceException: ### Error querying database. Cause: org.jboss.util.NestedSQLException: Error; - nested t…

ELK之LogStash插件grok和geoip的配置使用

本文针对LogStash常用插件grok和geoip的使用进行说明&#xff1a; 一、使用grok输出结构化数据 编辑 first-pipeline.conf 文件&#xff0c;修改为如下内容&#xff1a; input{#stdin{type > stdin}file {# 读取文件的路径path > ["/tmp/access.log"]start_…

【斗罗二】冰帝两次险些杀死雨浩,天梦哥求助伊老遭拒绝,霍云儿现身救儿子

Hello,小伙伴们&#xff0c;我是小郑继续为大家深度解析绝世唐门。 斗罗大陆动画第二部绝世唐门已经更新了&#xff0c;霍雨浩与冰帝完美融合&#xff0c;成功觉醒了第二武魂&#xff0c;霍挂的时代正式到来。只是在整个第19集中&#xff0c;官方做了大量的改编&#xff0c;不但…

Ubuntu 20.04 上安装和配置 neo4j

1. 进入要安装neo4j的ubuntu环境。 2. 添加Debian资源库。 java 1.8.xx版本对应neo4j 3.xx版本&#xff08;jdk 11版本对应neo4j 4.xx版本&#xff09;&#xff1a; &#xff08;1&#xff09;wget -O - https://debian.neo4j.com/neotechnology.gpg.key | sudo apt-key add…

Yolov8-pose关键点检测:模型轻量化创新 |多尺度空洞注意力(MSDA)结合C2f | 中科院一区顶刊 DilateFormer 2023.9

💡💡💡本文解决什么问题:多尺度空洞注意力(MSDA)采用多头的设计,在不同的头部使用不同的空洞率执行滑动窗口膨胀注意力(SWDA),全网独家首发,创新力度十足,适合科研 1)与C2f结合; MSDA | GFLOPs从9.6降低至8.5, mAP50从0.921降低至0.909,mAP50-95从0.697提…

uniapp缓存对象数组

需求&#xff1a;使用uniapp&#xff0c;模拟key&#xff08;表名&#xff09;增删改查对象数组&#xff0c;每个key可以单独操作&#xff0c;并模拟面对对象对应表&#xff0c;每个key对应的baseInstance 类似一个操作类&#xff0c;当然如果你场景比较简单&#xff0c;可以改…

AC修炼计划(AtCoder Regular Contest 167)

传送门&#xff1a;AtCoder Regular Contest 167 - AtCoder 再次感谢樱雪喵大佬的题解&#xff0c;讲的很详细&#xff0c;Orz。 大佬的博客链接如下&#xff1a;Atcoder Regular Contest 167 - 樱雪喵 - 博客园 (cnblogs.com) 第一题很签到&#xff0c;就省略掉了。 第二题…

数据结构——二叉树的公共祖先问题

数据结构——二叉树的公共祖先问题 236. 二叉树的最近公共祖先思路 235. 二叉搜索树的最近公共祖先思路1.递归2.迭代 236. 二叉树的最近公共祖先 236. 二叉树的最近公共祖先 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#x…

(矩阵) 289. 生命游戏 ——【Leetcode每日一题】

❓ 289. 生命游戏 难度&#xff1a;中等 根据 百度百科 &#xff0c; 生命游戏 &#xff0c;简称为 生命 &#xff0c;是英国数学家约翰何顿康威在 1970 年发明的细胞自动机。 给定一个包含 m n 个格子的面板&#xff0c;每一个格子都可以看成是一个细胞。每个细胞都具有一…

16-spring AOP核心对象的创建

文章目录 1. aop的几个重要概念2. aop bean definition3. AspectJPointcutAdvisor4.AopConfigUtils5.AnnotationAwareAspectJAutoProxyCreator6. 循环依赖 1. aop的几个重要概念 参考官方解释&#xff1a;https://docs.spring.io/spring-framework/docs/5.2.9.RELEASE/spring-…

大数据之LibrA数据库系统概览

实时监控 “实时监控”页面如图1所示&#xff0c;用户可单击刷新按钮手动刷新当前页面&#xff0c;也可在点刷新按钮前选择自动刷新时长&#xff0c;刷新时长包括&#xff1a;每30秒刷新一次、每60秒刷新一次、停止刷新。 实时监控数据&#xff08;监控时间轴产生的新曲线&am…

Oracle数据中如何在 where in() 条件传参

一、问题场景描述 在sql 条件中&#xff0c;如何在 where in()中想传入参数&#xff0c;如果直接 where in(:seqList)&#xff0c;当传入单个值&#xff0c;seqList: ‘80’ 是没问题的&#xff0c;但是初入多个值时&#xff0c;seqList: ‘80,90’ &#xff0c;因缺少单引号&…