volatile关键字
当一个变量被修饰为volatile关键字,那么某个线程修改了这个变量,其他变量能马上获取到最新修改的值。
volatile结合JMM分析
对于一个普通的共享变量,多个线程在操作它时,不能直接从主内存操作,必须在线程的私有栈操作。每个线程的私有栈都保存着共享变量的副本,先从主内存中得到最新的值,在副本中修改后,再写入主内存中。在多线程下,会出现在自己的线程里修改后,没有及时写入主内存,别的线程看到的是旧值而不是新值。
对于被volatile关键字修饰的变量,在使用这个变量前,JVM强制线程读取主内存中最新的值;在修改共享变量后,JVM强制线程立马将最新的值写入主内存中。
JMM通过happens-before原则,对volatile修饰的变量有以下保证:
对一个volatile域的写,happens-before于任意后续对这个volatile域的读。
volatile对于复合操作,是不会保证线程安全的。例:count ++,这个不是原子操作,可以分解为:
// count++分解为:
int count1 = count;
// 这时候,count的值可能已经被别的线程改了,但是count1还是原来的count值,导致计算错误
count1 = count1 + 1;
count = count1;
所以volatile最佳使用场景是:
- 共享变量多个线程读,一个线程写
- 共享变量改变的值不依赖于原值,如boolean类型
volatile实现内存可见性和有序性
volatile实现有序性是禁止指令重排序。
volatile实现内存可见性:
加入内存屏障和禁止重排序优化
- 对volatile变量进行写操作时,会在写操作之后加入store指令,强迫线程将最新的值写入主内存中
- 对volatile变量进行读操作时,会在读操作之前加入load指令,强迫线程从主内存重读该变量的值。