谈谈对volatile关键字的理解

#特性

volatile是 Java 语言提供的一种轻量级的同步机制,用来确保将变量得更新操作通知到其它线程。具备三种特性:

  • 保证变量的可见性;
  • 对于 volatile 修饰的变量进行单次读/写操作可以保证原子性,对于i++这样的多次操作不保证原子性;
  • 防止指令重排(通过在指令序列中插入内存屏障来禁止特定类型的处理器重排序)。

#与synchronized的区别

区别可以从以下四点阐述:

  • volatile关键字是线程同步的轻量级实现,其性能比synchronized关键字好。但是 volatile 关键字只能修饰变量而 synchronized 关键字可以修饰方法以及代码块。synchronized 关键字在 JDK1.6 之前是一种重量级锁,在 1.6 之后进行了一系列的优化(主要是为了减少获得锁和释放锁带来的性能消耗而引入偏向锁和轻量级锁使得效率有所提升),实际中使用 synchronized 的场景相对较多;
  • 多线程情况下访问 volatile 关键字修饰的变量不会造成阻塞,而 synchronized 关键字可能会造成阻塞;
  • volatile 可以保证变量的可见性,但不能完全保证数据操作的原子性,而synchronized技能保证变量可见性也能保证原子性;
  • volatile 关键字主要用于解决变量在多个线程之间的可见性问题,而 synchronized 关键字解决的是多个线程之间访问资源的同步性。

#使用场景

#单例模式(双检锁DCL)
public class Singleton {
    
    private volatile static Singleton singleton;
    
    private Singleton() {
    }
    
    public static Singleton getSingleton() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

使用 volatile 关键字修饰 singleton ,防止指令重排。如果不加 volatile 关键字,则会出如下问题:在执行if (singleton == null)判断时,有可能 singleton 对象正在初始化的过程中还未完成,因此会通过双重检查,然后又进行一次 singleton 对象的初始化,从而导致出现多个实例。