Volatile


volatile 是 Java 虚拟机提供的轻量级的同步机制,它可以保证可见性(缓存一致性协议)和有序性(禁止指令重排序,也就是通过内存屏障来实现),但是不保证原子性。

 

作用

 

volatile 作 用  保 证 变 量 对 所 有 线 程 的 可 见 性  禁 止 指 令 重 排  不 保 证 原 子 性

 

内存模型

Java***  Java***  Java***  工 作 内 存  工 作 内 存  工 作 内 存  Sava  Load  操 作  一 0  主 内 存

 

Happen Before

happens-before 原则,是 JMM 中非常重要的一个原则,它是判断数据是否存在竞争、线程是否安全的主要依据,依靠这个原则,我们可以解决在并发环境下两个操作之间是否存在冲突的所有问题。JMM 规定,两个操作存在 happens-before 关系并不一定要 A 操作先于B 操作执行,只要 A 操作的结果对 B 操作可见即可。

  • 程序顺序原则:一个线程内保证语义的串行性
  • volatile规则:volatile变量的写操作,先发生于读操作,这保证了volatile变量的可见性
  • 锁规则:解锁(unlock)必然发生在随后的加锁(lock)前
  • 传递性:A先于B,B先于C,那么A必然先于C
  • 线程的start()方法先于它的每一个动作
  • 线程的所有操作先于线程的终结(Thread.join())
  • 线程的中断(interrupt)先于被中断线程的代码
  • 对象的构造函数执行、结束先于finalize()方法

 

 

内存屏障

内存屏障其实也是一种JVM指令,Java内存模型的重排规则会要求Java编译器在生成JVM指令时插入特定的内存屏障指令,通过这些内存屏障指令来禁止特定的指令重排序。

另外内存屏障还具有一定的语义:内存屏障之前的所有写操作都要回写到主内存,内存屏障之后的所有读操作都能获得内存屏障之前的所有写操作的最新结果(实现了可见性)。因此重排序时,不允许把内存屏障之后的指令重排序到内存屏障之前。

 

 

常见问题

 

为什么无法保证原子性?

在插入内存屏障之前的操作并不是原子性的。多个线程可以修改,所以无法保证原子性。