volatile(使用内存屏障) 一般在多线程中用于线程间同步,与synchronized(使用临界区)相比,volatile相对轻量,不会引起线程上下文的切换和调度,但同步性较差;
内存屏障:
如果用内存屏障,JMM处理器要求Java编译器在生成指令序列时插入特定内存屏障指令来禁止特定重排序。
JMM定义了线程与主内存的抽象关系,线程有一个私有本地内存,保存了该线程使用到的主内存的副本拷贝,线程对变量的操作在本地内存中进行而不直接读写主内存中的变量。
例子:
public class ControlDep {
int a = 0;
volatile boolean flag = false;
public void init() {
a = 1; // 1
flag = true; // 2
//.......
}
public void use() {
if (flag) { // 3
int i = a * a; // 4
}
//.......
}
}
在init()方法中flag为volatile变量,A线程在写volatile变量之前所有可见的共享变量,在B线程读同一个volatile变量后,将立即变得对B线程可见。也就是说程序执行执行完第2步的时候,处理器会将第2步和其之前的所有结果强制刷新到主内存。也就是说a=1也会被强制刷新到主内存中。那么当另一个线程执行到步骤3的时候,如果判断到flag=true时,那么第4步处a一定是等于1的,这样就保证了程序的正确运行。
原理:
加入volatile关键字时,会多出一个lock前缀指令,lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),内存屏障会提供3个功能:
(1)它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障
的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
(2)它会强制将对缓存的修改操作立即写入主存;
(3)如果是写操作,它会导致其他CPU中对应的缓存行无效。
参考链接:https://blog.csdn.net/xiaolyuh123/article/details/103289570