Java多线程之多线程之volatile关键字及内存屏障实例解析关键字及内存屏障实例解析
volatile是JVM提供的一种最轻量级的同步机制,因为Java内存模型为volatile定义特殊的访问规则,使其可以实
现Java内存模型中的两大特性:可见性和有序性。这篇文章主要介绍了Java多线程之volatile关键字及内存屏障,
需要的朋友可以参考下
前面一篇文章在介绍Java内存模型的三大特性(原子性、可见性、有序性)时,在可见性和有序性中都提到了volatile关键字,那
这篇文章就来介绍volatile关键字的内存语义以及实现其特性的内存屏障。
volatile是JVM提供的一种最轻量级的同步机制,因为Java内存模型为volatile定义特殊的访问规则,使其可以实现Java内存模
型中的两大特性:可见性和有序性。正因为volatile关键字具有这两大特性,所以我们可以使用volatile关键字解决多线程中的
某些同步问题。
volatile的可见性的可见性
volatile的可见性是指当一个变量被volatile修饰后,这个变量就对所有线程均可见。白话点就是说当一个线程修改了一个
volatile修饰的变量后,其他线程可以立刻得知这个变量的修改,拿到最这个变量最新的值。
结合前一篇文章提到的Java内存模型中线程、工作内存、主内存的交互关系,我们对volatile的可见性也可以这么理解,定义
为volatile修饰的变量,在线程对其进行写入操作时不会把值缓存在工作内存中,而是直接把修改后的值刷新回写到主内存,
而当处理器监控到其他线程中该变量在主内存中的内存地址发生变化时,会让这些线程重新到主内存中拷贝这个变量的最新值
到工作内存中,而不是继续使用工作内存中旧的缓存。
下面我列举一个利用volatile可见性解决多线程并发安全的示例:
public class VolatileDemo {
//private static boolean isReady = false;
private static volatile boolean isReady = false;
static class ReadyThread extends Thread {
public void run() {
while (!isReady) {
}
System.out.println("ReadyThread finish");
}
}
public static void main(String[] args) throws InterruptedException {
new ReadyThread().start();
Thread.sleep(1000);//sleep 1秒钟确保ReadyThread线程已经开始执行
isReady = true;
}
}
上面这段代码运行之后最终会在控制台打印出: ReadyThread finish ,而当你将变量isReady的volatile修饰符去掉之后再运行
则会发现程序一直运行而不结束,而控制台也没有任何打印输出。
我们分析下这个程序:初始时isReady为false,所以ReadyThread线程启动开始执行后,它的while代码块因标志位isReady为
false会进入死循环,当用volatile关键字修饰isReady时,main方法所在的线程将isReady修改为true之后,ReadyThread线程
会立刻得知并获取这个最新的isReady值,紧接着while循环就会结束循环,所以最后打印出了相关文字。而当未用volatile修饰
时,main方法所在的线程虽然修改了isReady变量,但ReadyThread线程并不知道这个修改,所以使用的还是之前的旧值,因
此会一直死循环执行while语句。
volatile的有序性的有序性
有序性是指程序代码的执行是按照代码的实现顺序来按序执行的。
volatile的有序性特性则是指禁止JVM指令重排优化。
我们来看一个例子:
public class Singleton {
private static Singleton instance = null;
//private static volatile Singleton instance = null;
private Singleton() { }
public static Singleton getInstance() {
//第一次判断
if(instance == null) {
synchronized (Singleton.class) {
if(instance == null) {
//初始化,并非原子操作
instance = new Singleton();
}
}
}
评论0