volatile关键字
在Java中,volatile关键字用于声明变量,以确保对变量的读写操作直接在主内存中进行,而不是在线程的本地缓存中。volatile的主要作用是提供可见性和有序性保证,但它不保证原子性。
- 可见性(Visibility):
当一个共享变量被声明为volatile时,每次访问或修改这个变量时,都会立即写入主内存,并且每次读取这个变量时,都会从主内存重新读取。这确保了不同线程对该变量的修改对其他线程立即可见。 - 有序性(Ordering):
volatile可以防止指令重排序优化。编译器和处理器可能会对指令进行重排序以提高性能,但是当变量声明为volatile时,它会作为一个内存屏障,保证volatile变量前后的操作不会被重排序,从而保证了代码的执行顺序。
volatile防止指令重排(双重校验锁实现对象单例)
以如下双重校验锁实现对象单例举例:
public class Singleton {private volatile static Singleton uniqueInstance;private Singleton() {}public static Singleton getUniqueInstance() {//先判断对象是否已经实例过,没有实例化过才进入加锁代码if (uniqueInstance == null) {//类对象加锁synchronized (Singleton.class) {if (uniqueInstance == null) {uniqueInstance = new Singleton();}}}return uniqueInstance;}
}
当代码执行到:uniqueInstance = new Singleton();
时,背后实际有三步需要完成:
1、为 uniqueInstance 分配内存空间
2、初始化 uniqueInstance
3、将 uniqueInstance 指向分配的内存地址
但是因为java有指令重排从而优化代码的特性,执行顺序有可能变成 1->3->2。在单线程环境下是没有问题的,但是多线程环境下就可能出现问题。
例如,线程 T1 执行了 1 和 3,此时 T2 调用 getUniqueInstance()
后发现 uniqueInstance
不为空,因此返回 uniqueInstance
,但此时 uniqueInstance
还未被初始化。