- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
volatile是轻量级的同步机制,volatile可以用来解决可见性和有序性问题,但不保证原子性.
volatile的作用:
volatile通过内存屏障来维护可见性和有序性,硬件层的内存屏障主要分为两种Load Barrier,Store Barrier,即读屏障和写屏障。对于Java内存屏障来说,它分为四种,即这两种屏障的排列组合.
插入一个内存屏障,相当于告诉CPU和编译器先于这个命令的必须先执行,后于这个命令的必须后执行。对一个volatile字段进行写操作,Java内存模型将在写操作后插入一个写屏障指令,这个指令会把之前的写入值都刷新到内存.
当对volatile变量进行写操作的时候,JVM会向处理器发送一条Lock#前缀的指令 。
而这个LOCK前缀的指令主要实现了两个步骤:
原因在于缓存一致性协议,每个处理器通过总线嗅探和MESI协议来检查自己的缓存是不是过期了,当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存行置为无效状态,当处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据读到处理器缓存中.
缓存一致性协议:当CPU写数据时,如果发现操作的变量是共享变量,即在其他CPU中也存在该变量的副本,会发出信号通知其他CPU将该变量的缓存行置为无效状态,因此当其他CPU需要读取这个变量时,就会从内存重新读取.
总结一下:
happens-before 规则中有一条是 volatile 变量规则:对一个 volatile 域的写,happens-before 于任意后续对这个 volatile 域的读.
//假设线程A执行writer方法,线程B执行reader方法
class VolatileExample {
int a = 0;
volatile boolean flag = false;
public void writer() {
a = 1; // 1 线程A修改共享变量
flag = true; // 2 线程A写volatile变量
}
public void reader() {
if (flag) { // 3 线程B读同一个volatile变量
int i = a; // 4 线程B读共享变量
……
}
}
}
根据 happens-before 规则,上面过程会建立 3 类 happens-before 关系.
根据程序次序规则:1 happens-before 2 且 3 happens-before 4.
根据 volatile 规则:2 happens-before 3.
根据 happens-before 的传递性规则:1 happens-before 4.
因为以上规则,当线程 A 将 volatile 变量 flag 更改为 true 后,线程 B 能够迅速感知.
为了性能优化,JMM 在不改变正确语义的前提下,会允许编译器和处理器对指令序列进行重排序。JMM 提供了内存屏障阻止这种重排序.
Java 编译器会在生成指令系列时在适当的位置会插入内存屏障指令来禁止特定类型的处理器重排序.
JMM 会针对编译器制定 volatile 重排序规则表.
为了实现 volatile 内存语义时,编译器在生成字节码时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序.
对于编译器来说,发现一个最优布置来最小化插入屏障的总数几乎是不可能的,为此,JMM 采取了保守的策略.
在每个 volatile 写操作的前面插入一个 StoreStore 屏障.
在每个 volatile 写操作的后面插入一个 StoreLoad 屏障.
在每个 volatile 读操作的后面插入一个 LoadLoad 屏障.
在每个 volatile 读操作的后面插入一个 LoadStore 屏障.
volatile 写是在前面和后面分别插入内存屏障,而 volatile 读操作是在后面插入两个内存屏障.
在多线程环境中,原子性是指一个操作或一系列操作要么完全执行,要么完全不执行,不会被其他线程的操作打断.
volatile关键字可以确保一个线程对变量的修改对其他线程立即可见,这对于读-改-写的操作序列来说是不够的,因为这些操作序列本身并不是原子的。考虑下面的例子:
public class Counter {
private volatile int count = 0;
public void increment() {
count++; // 这实际上是三个独立的操作:读取count的值,增加1,写回新值到count
}
}
在这个例子中,尽管count变量被声明为volatile,但increment()方法并不是线程安全的。当多个线程同时调用increment()方法时,可能会发生以下情况:
在这种情况下,虽然increment()方法被调用了两次,但count的值只增加了1,而不是期望的2。这是因为count++操作不是原子的;它涉及到读取count值、增加1、然后写回新值的多个步骤。在这些步骤之间,其他线程的操作可能会干扰.
为了保证原子性,可以使用synchronized关键字或者java.util.concurrent.atomic包中的原子类(如AtomicInteger),这些机制能够保证此类操作的原子性:
public class Counter {
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.getAndIncrement(); // 这个操作是原子的
}
}
在这个修改后的例子中,使用AtomicInteger及其getAndIncrement()方法来保证递增操作的原子性。这意味着即使多个线程同时尝试递增计数器,每次调用也都会正确地将count的值递增1.
来自一线程序员Seven的探索与实践,持续学习迭代中~ 。
本文已收录于我的个人博客:https://www.seven97.top 。
公众号:seven97,欢迎关注~ 。
最后此篇关于volatile关键字最全原理剖析的文章就讲到这里了,如果你想了解更多关于volatile关键字最全原理剖析的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
如果我创建一个对象时没有使用 new 关键字,例如“Object s(someval)”,但该对象的构造函数使用了 new,当该对象超出范围时,是否会调用析构函数为其分配新的空间?我感觉好像是,但我不
在 SQL 语法中,我发现奇怪的规则表明 select * from ONLY (t1)是有效的 SQL。 我的问题是:什么是 ONLY在这种情况下是什么意思? 它在规范的“7.6 table ref
为什么使用 $(this) 而不是重新选择类很重要? 我在代码中使用了大量的动画和 CSS 编辑,并且我知道可以使用 $(this) 来简化它。 最佳答案 当您通过 jQuery 执行 DOM 查询(
我正在尝试使用 IN 关键字编写查询。 表A 属性标识、属性名称 表B key 、属性标识、属性值 根据提供的 key ,我想返回所有 attrName、attrVal 组合。结果将包含两个表中的列。
这个问题在这里已经有了答案: Why would you use "AS" when aliasing a SQL table? (8 个答案) 关闭 9 年前。 我不擅长写查询,但是从我开始使用
我读过,在 Java 中,您不必将 this 关键字显式绑定(bind)到对象,它由解释器完成。它与 Javascript 相反,在 Javascript 中你总是必须知道 this 的值。但是 Ja
Swift 中“with”关键字的用途是什么?到目前为止,我发现如果您需要覆盖现有的全局函数,例如 toDebugString,可以使用该关键字。 // without "with" you
这个问题在这里已经有了答案: What does the keyword "where" in a class declaration do? (7 个答案) 关闭 9 年前。 在下面的一段代码中(
免责声明:swift 菜鸟 您好,我刚刚开始学习 Swift,正在学习 Swift 编程语言(Apple 在 WWDC 期间发布的书籍),并且想知道“where”关键字是什么。它用于 let vege
深入研究文档后,我找不到以下问题的答案: 是否有任何理由反对使用 this 来引用当前对象,如下例所示? type MyStruct struct { someField string } fun
前言 最近在做THINKPHP开发项目中,用到了 parent:: 关键字,实际上 parent::关键字 是PHP中常要用到的一个功能,这不仅仅是在 THINKPHP 项目开发中,即使是一个小型
我们都知道且经常用到 unsigned 关键字,但有没有想过,与此对应的 signed 关键字有啥用? 复制代码 代码如下: int i = 0; signed
this关键字再java里面是一个我认为非常不好理解的概念,:)也许是太笨的原因 this 关键字的含义:可为以调用了其方法的那个对象生成相应的句柄。 怎么理解这段话呢? thinking i
一 什么是 synchronized synchronized 关键字提供了一种锁机制,能够确保共享变量互斥访问,从而防止数据不一致问题的出现。 synchronized 关键字包括 monitor
最近看了几篇 synchronized 关键字的相关文章,收获很大,想着总结一下该关键字的相关内容。 1、synchronized 的作用 原子性:所谓原子性就是指一个操作或者多个操作,要么全部执行并
在本教程中,您将借助示例了解 JavaScript 对象方法和 this 关键字。 在 JavaScript 中,对象也可以包含函数。例如, // object containing meth
有人可以解释一下 PHP“with”的作用吗? 示例开始: 假设我有一个类: \App\fa_batch 这句话有什么区别: $w = (with (new \App\fa_batch))
这个问题在这里已经有了答案: What is the difference between using the colon and as syntax for declaring type? (2
如果我在 WHERE 子句中使用以下任一项,是否会有很大不同: WHERE [Process Code] = 1 AND ([Material ID] = 'PLT' OR [Material ID]
This question is unlikely to help any future visitors; it is only relevant to a small geographic are
我是一名优秀的程序员,十分优秀!