java关键字volatile的理解

java关键字volatile的理解

年轻人 137 2022-10-20


简单的描述缓存一致性问题:对于某个共享变量,每个操作单元都缓存一个该变量的副本。当一个操作单元更新其副本时,其他的操作单元可能没有及时发现,进而产生缓存一致性问题。

缓存一致性问题非常常见,在Java中也有这样的案例。假设有一个变量a=1,它被3个线程所共享。Jvm在运行时,每个线程都会在自己的工作空间(高速缓存保存的副本,不是栈区)保存一份变量a的副本。如下图。



某个时刻,线程t1需要更新a=0。与此同时,线程t2需要读a的值,线程t3需要读a的值。由于这三个“动作”是并发进行的,很可能出现下面的结果:线程t2和线程t3仍然读到a=1。而我们希望的结果是,线程t2和线程t3读到a=0。但是,线程t2和线程t3何时再次从主内存中读取变量a的值是不受控制的。可能很快,也可能很慢。



为了解决类似这样的问题,Java内存模型(JMM)应运而生。它规定了必须要遵守哪些访问规则,以保证程序的正确性。下面是对Java内存模型的介绍:(选自官方文档

  • A memory model describes, given a program and an execution trace of that program。The Java programming language memory model works by examining each read in an execution trace and checking that the write observed by that read is valid according to certain rules.
  • Java内存模型描述了程序的执行过程。Java内存模型是这样工作的:它检查执行过程中的每一个读操作,并且按照某些规则来核对被当前读操作感知到的写操作是否合法。

在JMM众多的访问规则中,关于volatile有这样一条规则:(引用自Happens-before Order

  • A write to a volatile field happens-before every subsequent read of that field. 对一个volatile变量的写操作happen-before对这个变量之后的每一个读操作

happen-before的含义如下:(引用自Happens-before Order

  • If one action happens-before another, then the first is visible to and ordered before the second. 如果指令甲happens-before指令乙,那么指令甲必须排序在指令乙之前,并且指令甲的执行结果对指令乙可见。

从规则的定义可知,如果多个线程同时操作volatile变量,那么对该变量的写操作必须在读操作之前执行(禁止重排序),并且写操作的结果对读操作可见(强缓存一致性)。

正是由于JMM这样“明智”的限制,使得用volatile声明的变量总是能够在多线程中依旧保持其可见性。在之前的例子中,如果把变量a用volatile声明,那么当线程t1更新a=0时,与之并发执行的线程t2和线程t3读到的a的值就会是0了。

总结:volatile关键字

1.强刷主存,保证不同线程对变量的可见性

2.禁止指令重排序,保证写操作发生在读操作之前