java双检锁构造单例类的问题(jdk1.5前)

2019-03-07  本文已影响0人  蛋花汤汤
static Singleton instance = null;
    static Singleton getInstance(){
        if(instance == null){
            synchronized (Singleton.class){
                if(instance == null)
                    instance = new Singleton();
            }
        }
        return instance;
    }

以上代码是典型的java双检锁构造单例模式的代码。看上去两次判空+类锁保证了多线程下的安全,其实不然,这种写法依然存在问题。
问题出现在 instance = new Singleton(); 这句话上。
这句话就是初始化一个对象,理论上这个操作的步骤大概是下面这个样子的:

  1. 分配一块内存M;
  2. 在内存M上初始化Singleton对象
  3. 将内存M的地址赋给instance。
    实际上,jvm会对这个过程进行优化,优化过后的步骤是这样的:
  4. 分配一块内存M;
  5. 将内存M的地址赋给instance;
  6. 在内存M上初始化Singleton对象。
    那么问题来了,如果有两个线程A、B都在试图获取单例,A在执行到上述步骤2的时候,发生了线程切换,此时instance是被赋予了内存的地址的,所以不为空,这时B获得时间片,开始执行逻辑,走到第一句发现instance已经不为null,直接返回了这个引用。因为这个对象还没有初始化,后续通过这个引用方位内存上的对象时,会抛出NPE。
上一篇 下一篇

猜你喜欢

热点阅读