volatile是一个轻量级的锁(synchronized),如果一个变量使用volatile,则它比使用synchronized的成本更低,因为它不会引起线上上下文的切换和调度。

一个变量如果用volatile修饰了,则Java可以确保所有线程看到这个变量的值是一致的,如果某个线程对volatile修饰的共享变量进行更新,那么其他线程可以立马看到这个更新,这就是所谓的线程可见性。

注意:volatile不保证操作的原子性,但synchronized则可以保证。

volatile相对于synchronized稍微轻量些,在某些场合它可以替代synchronized,但是又不能完全取代synchronized,只有在某些场合才能够使用volatile。使用它必须满足如下两个条件:
1.对变量的写操作不依赖当前值;
2.该变量没有包含在具有其他变量的不变式中。

volatile经常用于两个两个场景:状态量标记、double check

double check示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Singleton {
private static volatile Singleton singleton = null;

private Singleton() {}

public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}

return singleton;
}
}

当然单例模式延迟初始化还可使用其他的方式,比如枚举、静态内部类。可以参考这篇文章:https://blog.csdn.net/goodlixueyong/article/details/51935526

注意:使用volatile做双重检查只有在jdk1.5或之后的版本正常,之前的版本由于JMM(java内存模型)仍然是有问题的。

参考:死磕Java并发:深入分析volatile的实现原理Java volatile关键字解惑