volatile关键字

JVM原则的先行发生原则(Happen-Before)

先行发生原则是 Java 内存模型中定义的两个操作之间的偏序关系。比如说操作 A 先行发生于操作 B,那么在 B 操作发生之前,A 操作产生的“影响”都会被操作 B 感知到。这里的影响是指修改了内存中的共享变量、发送了消息、调用了方法等。

自带的先行发生原则:

一、程序次序原则

在一个线程内部,按照代码的顺序,书写在前面的先行发生与后边的。或者更准确的说是在控制流顺序前面的先行发生与控制流后面的,而不是代码顺序,因为会有分支、跳转、循环等。

二、管程锁定规则

一个 unlock 操作先行发生于后面对同一个锁的 lock 操作。这里必须注意的是对同一个锁,后面是指时间上的后面

三、volatile 变量规则

对一个 volatile 变量的写操作先行发生与后面对这个变量的读操作,这里的后面是指时间上的先后顺序

四、线程启动规则

Thread 对象的 start()方法先行发生与该线程的每个动作。当然如果你错误的使用了线程,创建线程后没有执行 start 方法,而是执行 run 方法,那此句话是不成立的,但是如果这样其实也不是线程了

五、线程终止规则

线程中的所有操作都先行发生与对此线程的终止检测,可以通过 Thread.join()和 Thread.isAlive()的返回值等手段检测线程是否已经终止执行

六、线程中断规则

对线程 interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过 Thread.interrupted()方法检测到是否有中断发生。

七、对象终结规则

一个对象的初始化完成先行发生于他的 finalize 方法的执行,也就是初始化方法先行发生于 finalize 方法

八、传递性

如果操作 A 先行发生于操作 B,操作 B 先行发生于操作 C,那么操作 A 先行发生于操作 C。

volatile禁止指令重排

Volatile实现禁止指令重排优化,从而避免了多线程环境下程序出现乱序执行的现象
但是volatile并不能实现线程同步,因为他无法保证操作的原子性
首先了解一个概念,内存屏障(Memory Barrier)又称内存栅栏,是一个CPU指令,它的作用有两个:
1. 保证特定操作的顺序
2. 保证某些变量的内存可见性(利用该特性实现volatile的内存可见性)
由于编译器和处理器都能执行指令重排的优化,如果在指令间插入一条Memory Barrier则会告诉编译器和CPU,不管什么指令都不能和这条Memory Barrier指令重排序,也就是说 通过插入内存屏障禁止在内存屏障前后的指令执行重排序优化。 内存屏障另外一个作用是刷新出各种CPU的缓存数,因此任何CPU上的线程都能读取到这些数据的最新版本。
volatile关键字