对volatile int的单写多读??

文章讨论了volatile int在多线程环境中的安全性,指出volatile并不能保证跨线程的写操作顺序,可能导致不确定性结果。编译器、CPU、操作系统和内存管理机制的复杂交互使得这种单写多读操作并不一定是安全的。volatile的关键在于防止编译器优化,但并不能防止指令重排序,尤其是在多核CPU环境下。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我已经不止一次听到关于volatile int的安全读写方面的谬论了。

最常见的是所谓的volatile int的变量的单写多读操作是多线程安全的。

这个结论很搞笑,因为每当支持这个节论的人给我讲一大堆诸如锁总线,原子指令方面的东西时,(权且当他们都说的全对)我几乎都可以反问他:根据你说的东西可以得到一个结论,volatile int是也多线程写安全的(串行的),volatile int就是原生的信号量。那些搞并发编程的人难道都是吃饱了撑的,搞什么锁来玩的?

 

好了,谈些基本点,基于c语言标准:

1。volatile的行为是不可移植的(基于编译器,编译器基于cpu)。c语言另外一个不可移植的东西是位域。

2。volatile的行为编译器至少都当作io行为(最低限度的可移植语义,也是最好理解的一种说法,可惜很多人都不明白io行为意味着什么)。

3。volatile变量的读写操作将禁止该操作后的指令在该操作之前执行,之前的指令也不得推后执行。(禁止执行流水线,矢量化等等常见优化,总之跨volatile不能打乱,合并原有的语句来进行优化)

4。c代码编译成汇编之后,什么volatile之内的关键字全没了,只有一堆汇编指令。

 

5。多线程的语义取决于实现(基于操作系统,操作系统基于cpu,实现代码也都是汇编)。不同的操作系统的多线程实现和调度可能基于不同的原理,和内存管理机制往往关系也不小。这也是win32居然有用户态的critical section这样的同步原语供大家使用,因为它专著x86而linux需要跨cpu,前者就可以直接封装i386汇编来玩,而且恰好win32的线程可以不用进内核态进行系统调用就休眠,唤醒自己(这就是原生多线程系统的好)。

6。c语言的标准和多线程编程没有任何关系,c语言不保证代码在多线程中执行的情况。c的标准出现的可比最早的多线程操作系统win和solary早多了,不可能预测生后事。不同的系统多线程实现更是千奇百怪,很难提炼出一个公有的底层特性。你看看j

<think>嗯,用户想了解Java中的volatile关键字在内存屏障中的作用,具体是作为屏障还是屏障。首先,我需要回顾volatile的基本作用,它保证可见性和有序性。根据之前学过的内容,volatile变量在修改后会立即刷新到主内存,而其他线程取时会从主内存重新获取,避免缓存不致的问题。 接下来,内存屏障的概念。内存屏障分为屏障(Load Barrier)和屏障(Store Barrier),它们分别防止指令重排序和确保内存可见性。那volatile是如何利用这两种屏障的呢?记得volatile操作会在之后插入屏障,确保之前的所有修改都同步到主存;而操作前会插入屏障,保证之后的取都能看到最新的值。同时,这些屏障也限制编译器和处理器的重排序,保证有序性。 需要确认下具体的JVM实现,比如在x86架构下,volatile操作会生成带有lock前缀的指令,相当于内存屏障。而操作可能不需要显式屏障,因为x86有较强的内存模型,但其他平台可能不同。所以,volatile的屏障插入是平台相关的,但JVM会处理这些差异,确保跨平台的致性。 用户可能还混淆了屏障和屏障的具体应用场景。比如,屏障确保之前的操作对其他线程可见,屏障确保之后的操作获取最新值。volatile操作分别对应这两种屏障,从而实现了其内存语义。 另外,需要引用提供的资料。引用[3]提到volatile解决可见性和有序性,但没有通过线程间通信,这支持了内存屏障的作用。引用[2]讨论了volatile的内存语义和屏障实现,而引用[1]强调屏障策略保证正确性。这些都可以用来支持回答。 总结来说,volatile操作后插入屏障,在操作前插入屏障,确保内存可见性和禁止重排序。需要明确区分这两种屏障的作用,并结合不同处理器的实现差异,说明JVM如何统处理这些屏障,保证跨平台正确性。</think>### Java volatile 关键字与内存屏障的作用分析 #### 1. volatile 关键字的核心作用 - **内存可见性**:volatile 变量修改后立即同步到主内存,其他线程取时强制从主内存获取最新值,避免缓存不致问题[^3]。 - **有序性**:禁止编译器和处理器对 volatile 变量的操作进行指令重排序[^2]。 #### 2. 内存屏障的具体实现 volatile 通过 **屏障(Store Barrier)** 和 **屏障(Load Barrier)** 实现上述特性: 1. **操作(Store)**: - 在 volatile 变量入后插入 **StoreStore 屏障**,确保之前的所有普通操作对其他线程可见。 - 插入 **StoreLoad 屏障**,强制将本地内存刷新到主内存。 ```java volatile int x = 0; x = 1; // 操作后插入屏障 ``` 2. **操作(Load)**: - 在 volatile 变量取前插入 **LoadLoad 屏障**,禁止后续普通操作与当前 volatile 重排序。 - 插入 **LoadStore 屏障**,禁止后续普通操作与当前 volatile 重排序。 ```java int y = x; // 操作前插入屏障 ``` #### 3. 处理器平台的差异 - **x86 架构**:由于强内存模型特性,仅需在 volatile 操作后插入 **StoreLoad 屏障**(通过 `LOCK` 前缀指令实现)[^1]。 - **ARM/POWER 架构**:需显式插入屏障和屏障,确保跨平台致性。 #### 4. 示例验证 ```java // 线程A volatile boolean flag = false; data = 42; // 普通操作 flag = true; // 屏障确保 data 入主内存 // 线程B while (!flag); // 屏障强制从主内存取 flag System.out.print(data); // 必然输出 42 ``` #### 5. 性能影响 由于内存屏障会限制指令级并行和缓存优化volatile 变量的成本高于普通变量,需谨慎使用。 ---
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值