零、前期准备
三大性质,原子性,可见性,有序性简绍:https://www.jianshu.com/p/cf57726e77f2
首先说下volatile的性质:可见性,有序性。
一、结合实例说明
1,结合单例模式说明
单例模式的其中一种实现:
public class Singleton {
// private volatile static Singleton instance = null;
private static Singleton instance = null;
private Singleton() {}
public static Singleton getInstance() {
// 1,第一个IF判断
if (instance == null) {
// 2,同步代码块
synchronized (Singleton.class) {
// 3,第二个IF判断
if (instance == null) {
// 4,实例化对象
instance = new Singleton();
}
}
}
// 5,返回对象
return instance;
}
}
现在线程t1,t2同时执行第1步;
执行第2步的时候,t1拿到了锁,t2进入等待,此时t1的instance等于null,t2的instance等于null;
t1执行完同步代码块之后,t2开始执行同步代码块,那么重点来了,
t2执行第3步的时候,此时t2的instance是否等于null?
如果等于null的话,instance声明的时候前面必须要加volatile,
因为volatile声明的变量具有可见性,当t1静态代码块执行完成之后,会告诉t2,instance已经被改变,
这样t2执行第3步时,执行结果为false,不会继续往下执行,从而保证该类的实例单一性。
事实上,此时t2的instance并不等于null。那么为什么instance明明没有加volatile声明,而t2的instance却不为null?
下面引用别人博客的话来解释(博文地址:https://www.jianshu.com/p/d53bf830fa09):
synchronized代码块中一个线程释放锁的时候会将值刷新到主内存中,其他线程获取锁时会强制从主内存中获取最新的值。
这就解释了为什么不用加volatile,t2的instance会不等于null。
实际上,我最初反复始测试的时候,就没加volatile声明,但是每个线程拿到的实例却都是相同的,这就让我很疑惑,后来我看到了这篇博文就豁然开朗,其实synchronized拥有三大性质,即原子性,可见性,有序性。所以t2执行第3步的时候,instance不等于null。
其它的应用场景等遇到了,再更新,上面的貌似和volatile本身没多大关系。。。。