好吧,这里我只想说说volatile在JMM中的语义。
当我们在使用volatile的时候,实际上它表达了下面那么些意思。
1. 可见性。
这个是大多数人都知道的一个特质, JAVA的线程有自己的工作内存区,与主存区不同,当我们对变量使用了volatile后,那么不管对这个变量的读或写,都会在主存中进行,而不会在处理器的缓存或者寄存器中进行。这个很好理解。
2. 禁止CPU指令的重排序
这个特质的理解稍微要花点脑细胞, 首先我们需要一点premilinary, 当我们的程序编写好了以后,会被翻译成指令集并被加载到内存中去运行。但是,在CPU真正执行的时候,处于性能方面的考虑,这些指令的执行不一定会按照程序中的顺序进行,只要保证其程序执行语义没有变化即可。
来看下代码,
class VolatileExample {
int x = 0;
volatile boolean v = false;
//in thread A
public void writer() {
x = 42;
v = true;
}
//in thread B
public void reader() {
if (v == true) {
//uses x - can we see x is 42?
}
}
}
在这种情况下,当thread A 执行完后,在thread B中能看到x等于42吗?(变量v肯定可以看到,根据可见性可以推断出来) 好吧,在旧的JMM模型下,答案是不一定。原因就是CPU指令在执行时的重排序。在旧的JMM模型下,只规定了volatile变量和volatile变量之间不能进行重排序,但是并没有保证volatile变量和non-volatile变量之间不能进行重排序,所以, 当在thread A中,指令的执行可能是:
v = true;
x = 42;
这样,当thread B 看到v为true的时候,x实际上还没有执行,所以值不是42.
慢!眼尖的同学可能看出来了, 你说的这个跟重排序实际上没有关系呀,这个应该算是变量x的可见性问题,因为变量x不是声明为volatile的。
好吧,我承认我偷懒了,在描述volatile变量可见性特质的时候,在新的JMM模型下,当对volatile变量进行写的时候,该线程(这里是thread A)所能看到变量(比如说变量x),都会一起刷新到主存中。这个也就是为什么我们会说对volatile变量的写操作,实际上等价于使用了synchronized关键字后释放monitor时产生的效果。 在这个前提下,上面的问题的确是CPU指令重排序的问题。
但是幸运的是,JMM随后提出了happen-before原则来fix了这个问题(主要是volitale变量和non-volatile变量之间的重排序问题。)
这里我只挑跟这个问题相关的三条原则来进行讲解,其余的可以到官方文档去查看。
1. 单线程原则, 在单线程执行的环境下,指令的执行是跟程序代码的执行顺序一致。 对于上面的例子来说,在程序代码顺序上,x=42 先于 v=true, 那么在内存指令执行的时候也是如此。
2. volatile变量原则,对volatile变量的写操作要优先于对volatile变量的读操作。
3. 转递性原则,如果A操作先于B操作,B操作先于C操作,那么A操作肯定先于C操作。
还是上面的例子,先用单线程原则,可以判断出,在thread A的执行中, x=42肯定要优先于v=true进行执行, 而在thread B的执行中,对v的读取操作肯定要优先于对x的使用操作。
接着再使用volatile变量原则,可以判断,对v的写肯定要先于对v的读, 最后再根据转递性原则, 可以推出在thread A中x=42的赋值操作肯定要先于thread B中对x的使用, 也就是说,当v读取出来是为true的时候,x肯定是42. 指令不会进行重排序。
那如果我们将x=42,v=true的语句倒过来呢?
class VolatileExample {
int x = 0;
volatile boolean v = false;
public void writer() {
//颠倒赋值给x,v的顺序。
v = true;
x = 42;
}
public void reader() {
if (v == true) {
//uses x - can we see x is 42 here?
}
}
}
我想通过上面的分析,各位同学自己应该也能推断出来了吧。:)
分享到:
相关推荐
本文将深入探讨volatile的含义、陷阱及其正确使用方式。 首先,volatile关键字的目的是告诉编译器,某个变量的值可能会在编译器无法察觉的情况下改变,例如由中断服务程序或并行硬件操作更改。这意味着每次访问该...
在"Java并发编程(18)第五篇中volatile意外问题的正确分析解答"这篇文档中,作者深入探讨了这些问题并提供了详细的解决方案。 首先,我们要明确volatile的两个主要特性:一是保证了共享变量的可见性,即当一个线程...
- **禁止指令重排序**:volatile保证了内存语义的有序性,防止编译器和处理器进行过于激进的优化导致数据一致性问题。 - **不保证原子性**:虽然volatile可以保证可见性,但不能保证对变量的操作是原子性的,如int...
下面我们将深入探讨`volatile`关键字的原理、使用场景以及与`synchronized`的区别。 一、`volatile`关键字的语义分析 1. **保证可见性**:当一个线程修改了`volatile`变量的值,其他所有线程都能立即看到这个变化...
本文将深入探讨这两种机制的原理,以及它们在实际编程中的应用。 首先,volatile关键字是Java中用于线程同步的一种轻量级机制。它主要有三个核心特性: 1. 可见性:当一个线程修改了volatile变量,其他所有线程都...
1. ** volatile关键字**:volatile变量在JMM中有特殊的语义,它可以确保对volatile变量的修改对其他线程是立即可见的,避免了线程工作内存与主内存数据不一致的情况。在案例中,如果包子的状态(是否有包子)使用...
下面是一些`volatile`关键字常见的使用场景: 1. **中断服务程序**:在中断服务程序中,我们可能需要修改一个变量来向其他线程或函数发送信号。这个变量需要是`volatile`的,因为它可能在中断处理程序执行期间被...
"04 并发编程专题06.zip"这个压缩包文件包含了两个部分:"JMM&volatile详解(下)(1).vep"和"JMM&volatile详解(下)(2).vep",它们着重探讨了Java内存模型(JMM)以及volatile关键字的深入理解。 Java内存模型...
- **volatile变量语义的加强**:在JSR-133之前,对volatile变量和非volatile变量的访问可以自由排序,但在新的规范中,volatile变量的操作具有了获取(acquire)和释放(release)语义,这意味着对volatile变量的...
从重排序的概念出发,我们探讨了如何使用`volatile`关键字以及`final`域来确保多线程程序的一致性和可见性。此外,还讨论了CAS操作及其潜在的ABA问题,并提出了解决方案。这些知识点对于理解和开发高性能的多线程...
JSR-133规范增强了volatile的内存语义,确保了volatile变量的有序性和可见性,这使得volatile在多线程程序中被广泛使用。 综上所述,Java内存模型是一个复杂的系统,它涉及了线程间的通信与同步、共享变量的访问...
这篇论文"具有松弛依赖关系的C11程序的Owicki Gries推理(扩展版)"深入探讨了如何将这一推理方法应用到C11标准的程序中,这是C/C++的2011年版本,其内存模型相当复杂。 C11标准引入了弱内存模型,允许数据在不同...
Java 内存模型(JMM,Java Memory Model)是 Java 语言的核心组件之一,它定义了 Java 程序中内存的行为和语义。本文将深入探讨 JMM 的设计原理和实现机理,通过结合实际的代码实验和分析,帮助读者更好地理解 Java ...
在本文中,我们将深入探讨Java内存屏障的概念、原理和应用,了解它在JVM并发机制中的重要作用。 一、内存屏障的定义和原理 内存屏障是一组处理器指令,用于实现对内存操作的顺序限制。它可以强制处理器按照特定的...
本文将详细探讨多线程和并发中的一些重要知识点,包括缓存一致性问题、volatile关键字的内存语义等,这些内容在各大公司的笔试面试中都是高频考点。 首先,让我们来解释一下什么是缓存一致性问题。当处理器执行计算...
作者阐述了`volatile`关键字的语义,如何保证并发环境下的数据一致性,并通过实例演示了如何在单例设计模式中应用`volatile`,以实现线程安全的单例。 第四部分是多线程设计架构模式,涵盖了多种用于提高并发性能...
本书不仅介绍了C++11和C++14所引入的新特性,如自动类型推导、移动语义、lambda表达式和并发支持等,更深入讲解了如何有效地使用这些特性,以便编写出正确、高效、可维护和可移植的现代C++代码。 书中涵盖的知识点...
此外,还有其他一些happens-before规则,如 volatile读写规则、初始化顺序规则等,它们共同保证了并发环境下的正确性。 了解这些基础知识后,开发者可以使用synchronized、volatile、final关键字以及ThreadLocal等...
9. **Java内存模型**:深入解析Java内存模型(JMM),理解数据一致性问题,如volatile的内存语义和happens-before原则。 10. **并发编程实战**:提供实际案例分析和练习,帮助读者将理论知识应用于实际项目,增强...