一,.volatile关键字的两层语义:
(一),一旦一个共享变量被volatile修饰之后,那么就具备了两层语义:
1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
2)禁止进行指令重排序。
(二),内存屏障有两个能力:
1. 阻止屏障两边的指令重排序
2. 强制把写缓冲区/高速缓存中的脏数据等写回主内存,让缓存中相应的数据失效
(三),volatile只保证可见性,不保证原子性;
volatile方式的i++,总共是四个步骤:
Load、Increment、Store、Memory Barriers。
(四)下面程序是:主线程修改非volatile类型的全局变量flag,子线程轮询flag,如果flag发生变动,则程序退出。但是如果实际运行这段代码会造成死循环,程序无法正常退出。这个现象是由于flag变量不是volatile的,主线程对flag的修改不一定能被子线程看到而引起的。
public class VisibilityDemo {
private volatile boolean flag=true;
//private boolean flag=true;
//-server -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:+LogCompilation -XX:LogFile=jit.log
public static void main(String[] args) throws InterruptedException {
VisibilityDemo demo1=new VisibilityDemo();
new Thread(new Runnable() {
@Override
public void run() {
int i=0;
System.out.println(Thread.currentThread().getName());
while(demo1.flag){
synchronized (this){
i++;
}
}
System.out.println(i);
}
}).start();
// System.out.println("即将sleep的Thread是:"+Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(2);
demo1.flag=false;
System.out.println("被置为false了");
}
}
加上volatile之后,程序正常退出,通过javap命令查看,有ACC_volatile命令,意思是禁止缓存。
遵循Happens-before原则。