这里仅讲解之前出现的单例实现,出现两个问题

    • 问题1:为什么要在INSTANCE对象前用volatile关键字修饰?
    • 问题2:为什么在synchronized块中仍要再加入一个INSTANCE的空判断? ```java import com.sun.scenario.animation.shared.SingleLoopClipEnvelope;

    public class Singleton {

    1. //构造方法设置为private,类外部不可以new出对象
    2. private Singleton(){}
    3. //问题1:解释为什么要加 volatile?
    4. private volatile static Singleton INSTANCE = null;
    5. public static synchronized Singleton getINSTANCE(){
    6. if(INSTANCE==null){
    7. synchronized (Singleton.class){
    8. // 为什么要加为空判断,之前不是判断过了嘛吗
    9. if(INSTANCE==null){
    10. INSTANCE = new Singleton();
    11. }
    12. }
    13. }
    14. return INSTANCE;
    15. }

    }

    ```

    问题1:
    volatile是为了防止指令重排序,当第一次创建INSTANCE对象时,多线程情况下由于指令重排列可能会造成结果错误。

    问题2:

    考虑刚开始创建INSTANCE的情景,获得锁的线程(线程t1)会进入INSTANCE的创建流程,如果线程t1因为时间片用尽而在创建实例之前就切换,其它线程会通过 INSTANCE==null 的检查,并阻塞在synchronized处,当线程t1执行完synchronized块释放锁后,其它阻塞的线程会进入synchronized块继续执行,这时如果不再次判断 INSTANCE 是否为空,还会再次执行 INSTANCE=new Singleton() 这行代码,从而更新对象值,如果有n个线程阻塞住,那么即会重新创建n次。问题2只会出现在刚创建 INSTANCE 对象的情况,如果实例已经创建,再调用方法则无法通过 INSTANCE==null 的检查,不会进入synchronized块,直接返回已经创建的实例。