Volatile与JMM

2024-03-13 21:44
文章标签 volatile jmm

本文主要是介绍Volatile与JMM,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

被Volatile修饰的变量有两大特点

可见性

有序性(禁重排)

如何保证的?内存屏障

Volatile的内存语义

当写一个Volatile变量的时候,JMM会把该线程对应的本地内存共享变量值立即刷新回主内存。

当读一个Volatile变量的时候,JMM会把本地内存置为无效,重新回到主内存中读取最新共享变量。

内存屏障

内存屏障前的所有写操作都要写回主内存

内存屏障之后的所有操作都能获得内存屏障之前的所有写操作的最新结果(实现了可见性)

看到写屏障:把这个指令之前的全部写回主内存

看到读屏障:保证了读取到的数据都是最新的

写屏障(Store Barrier)

写指令之后插入

读屏障(Load Barrier)

读指令之前插入

源码分析

度屏障

写屏障

读写混合

Unsafe.class 一定会对应 Unsafe.java

C++代码

细分4种

禁重排

其他情况随便编译器怎么重排序都行

Volatile插入读屏障示意图

Volatile插入写屏障示意图

保证可见性

案例1

结果

程序无法结束

原因:

案例2

将变量声明为volatile

结果

程序正常结束,灯灭了

volatile变量的读写过程

t1线程:

1.先从主内存中读取到自己的工作内存

2.然后use,使用这个变量,当前就一直在while循环里

这里切回main线程看:

1.先从主内存中读取到自己的工作内存

2.然后use,使用这个变量

3.传给cpu,把变量修改为false后,赋值写回工作内存

4.main线程准备把修改写回主内存了,这步要加锁,因为其他线程可能也在往回写,会发生线程安全问题,不就乱了。所以这步一定会加锁的

5.加锁后会清空工作内存中的值,也就是说其他线程手中持有的那份会作废掉,请他们再重新从主内存中重读一份或者重新赋值。

6.此时main线程写完了,立刻解锁,

这里切回t1线程看:

此时工作内存中的变量已经作废了,重新从主内存中拉取最新值为false

t1线程while循环退出

程序结束。

没有原子性

案例1

正常情况:

10个线程 操作1000次 应该是1w

结果:

案例2

此时将变量修改为volatile,同时去除Synchronized关键字

结果:

volatile不具备原子性 不等于1w

读取和赋值一个普通变量的情况

不保证原子性

number++这个操作在java代码看只有一行,但底层其实有3步

1.数据加载

2.数据计算

3.数据赋值

虽然读取到的数据都输最新的,但是写操作可能会出现丢失问题,无法保证原子性。

加了Synchronized关键字的情况

线程A加锁把5改成6,此时线程B原先读的5作废,重新读到6,+1改成7,结果正确。

不加Synchronized关键字的情况

线程B的操作直接作废,比如读到了5然后+1,但还没来得及写,线程A先一步完成,直接把线程B的操作全部作废,产生了写丢失,线程提前结束。

number++字节码分析

原子性:是指一个操作不能被中断,就算在多线程的环境下,也不应该受到其他线程的影响。

建议

指令禁重排

案例1

这里需要加入volatile禁止指令重排序

否则在多线程环境下,i=2和flag=true没有数据依赖性有可能交换顺序,read方法的结果就不可控了

volatile日常使用场景

DCL双端锁单例写法

隐患位置代码:

单线程环境下:

多线程环境下:

不加volatile

总结

可见性

volatile写

volatile读

字节码层面

内存屏障是什么

这篇关于Volatile与JMM的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/806293

相关文章

关键字synchronized、volatile的比较

关键字volatile是线程同步的轻量级实现,所以volatile性能肯定比synchronized要好,并且volatile只能修饰于变量,而synchronized可以修饰方法,以及代码块。随着JDK新版本的发布,synchronized关键字的执行效率上得到很大提升,在开发中使用synchronized关键字的比率还是比较大的。多线程访问volatile不会发生阻塞,而synchronize

关键字volatile有什么含意?

1. 并行设备的硬件寄存器。存储器映射的硬件寄存器通常加volatile,因为寄存器随时可以被外设硬件修改。当声明指向设备寄存器的指针时一定要用volatile,它会告诉编译器不要对存储在这个地 址的数据进行假设,也就是要去相应的内存地址里取。 2. 一个中断服务程序中修改的供其他程序检测的变量。volatile提醒编译器,它后面所定义的变量随时都有可能改变。因此编译后的程序每次需要存储或读取这

java内存模型及volatile关键字

文章目录 一、基本概念二、java内存模型三、volatile关键字 一、基本概念 在并发编程过程中,我们经常会遇到三类问题:原子性问题,可见性问题,有序性问题。下面我们来介绍一下和这些问题相关的三个概念。 1.原子性 也就是执行一个操作,要不全部执行成功,要不执行失败。比如a=0,这个操作就是原子性的,要么赋值成功,要么赋值失败。再比如a++操作,这个操作就不是原子性的,它是三

【编程底层思考】详解Java内存模型(JMM)原理及其作用

Java内存模型(Java Memory Model, JMM)是Java虚拟机(JVM)的一个核心概念,它定义了Java程序中各种变量(线程共享变量)的访问规则,以及在并发环境下,为了确保数据的可见性、原子性和有序性,线程之间如何协作。 作用 确保数据的可见性:在多线程环境中,一个线程修改了共享变量的值,其他线程能够看到这个修改。保证数据的原子性:复合操作(例如自增操作 i++)在多线程环境

Java memory model(JMM)的理解

总结:JMM 是一种规范,目的是解决由于多线程通过共享内存进行通信时,存在的本地内存数据不一致、编译器会对代码指令重排序、处理器会对代码乱序执行等带来的问题。目的是保证并发编程场景中的原子性、可见性、有序性。 总结的很精辟! 感谢Hollis总结

Java并发编程--深入理解volatile关键字

前言 一个月以前就准备写篇关于volatile关键字的博客,一直没有动笔,期间看了大量的文章,发现一个小小volatile关键字竟然涉及JMM(Java memory model),JVM(Java virtual machine),Java多线程同步与安全各个方面的知识,写起了非常的困难,后面附带的参考文献仅仅是我看过文献的一部分。 Java memory model(Java内存模型)

java volatile变量及其使用场景

java中的一种稍弱的同步机制,就是volatile变量,用于确保将变量的更新操作通知到其他线程。 变量声明为volatile后: (1)编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序(重排序不懂的,可以自行百度,需要理解)。 (2)volatile变量不会被缓存在寄存器或对其他处理器不可见的地方 因此volatile变量总是会返回最新的值。

【JUC】10-Java内存模型JMM

1. JMM 通过JMM来实现和主内存之间的抽象关系。屏蔽各个硬件平台和操作系统的内存访问差异以实现让Java程序在各种平台下都能达到一致的内存访问效果。 三大特性:原子性:互斥,同时成功或失败。有序性:指令重排序后有序。可见性:当一个线程修改了某一个共享变量的值,其他线程是否能够立即知道该变更,JMM规定了所有变量都存储在主内存中。   线程拷贝共享变量的副本,进行操作,然后再写入主内存。

【编程底层思考】Java中volatile关键字的使用和作用

在编程中,volatile 关键字是一个类型限定符,它用来告诉编译器,即使这个变量被频繁地访问,也不应该优化掉对它的读写操作。volatile 通常用于多线程编程中,特别是在嵌入式系统或硬件接口编程中,用来确保对某些变量的访问是按照代码的顺序执行的,而不是被编译器重排序。 以下是 volatile 关键字的一些使用场景和作用: 防止编译器优化:编译器在编译代码时,可能会对代码进行优化,以提高程序

J.U.C Review - volatile / synchronized / 锁 深入剖析

文章目录 几个基本概念内存可见性重排序happens-before规则 volatile的内存语义内存可见性禁止重排序内存屏障 volatile的用途总结 synchronized与锁Synchronized关键字Java对象头无锁、偏向锁、轻量级锁和重量级锁偏向锁实现原理撤销偏向锁 轻量级锁重量级锁 锁的升级流程各种锁的优缺点对比 几个基本概念 内存可见性 在Jav