美文网首页程序员
单例模式和volatile关键字

单例模式和volatile关键字

作者: 王小贱_ww | 来源:发表于2017-10-23 16:16 被阅读63次

  越来越感觉编程的世界是真正符合自然的世界,真正遵循自然的规律。在程序的世界中事情几乎是平等的,即使不平等也是有据可循,任何技术问题也可讨论的,无论结果如何,总是0与1的差别。 同样真实世界中的事物放到程序世界中也变得那么客观起来,正如这篇文章的主角Singleton Design Pattern一样。
  单例模式可以有多种实现方法,需要根据情况作出正确的选择。

  • 饿汉式
public class Singleton {
    
    private static Singleton mSingleton = new Singleton();

    public static Singleton getInstance() {
        return mSingleton;
    }
}

缺点:在类加载的时候就完成了初始化,所以类加载比较慢

  • 懒汉式
public class Singleton {

    private static Singleton mSingleton;

    public static Singleton getInstance() {
        if (mSingleton == null) {
            mSingleton = new Singleton();
        }
        return mSingleton;
    }
}

缺点:在多线程情况上不能正常工作

  • 双重检查锁定(double-checked locking)
public class Singleton {

    private static Singleton mSingleton;

    public static Singleton getInstance() {

        if (mSingleton == null) {
            synchronized (Singleton.class) {
                if (mSingleton == null) {
                    mSingleton = new Singleton();
                }
            }
        }
        return mSingleton;
    }
}

缺点:在多线程运行的时候,mSingleton可能报空指针的错误。假设线程A运行getInstance()方法,当运行 mSingleton = new Singleton()的时候,线程B也调用getInstance()方法,因为mSingleton !=null(但实际上初始化有问题),直接返回mSingleton ,导致空指针问题。WTF?
  这是因为 mSingleton = new Singleton()这一步操作不是原子性操作(所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch ),在执行的过程中,需要3步处理1.mSingleton 分配内存 2.mSingleton 调用起构造函数 3.对mSingleton 指向内存分配区域 1--2--3,但有点时候jvm会将其重排序,可能1--3--2,在线程B调用的时候,虽然mSingleton 不是null,但它可能没有进行初始化,导致空指针。

  • volatile关键字
     volatile能解决上面这种问题
    private  volatile static Singleton mSingleton;

mSingleton现在由volatile 关键字修饰,禁止重排序并且保证了变量的可见性。

  • 静态内部类
public class Singleton {

    public static Singleton getInstance() {
        return Holder.mSingleton;
    }

    private static class Holder {
        private static Singleton mSingleton = new Singleton();
    }

}

  内部类分为对象级别和类级别,类级内部类指的是:有static修饰的成员变量的内部类。如果没有static修饰的成员变量的内部类成为对象级内部类。
  类级内部类相当于外部类static成员,不存在依赖关系,相互独立,只有在第一次使用时才会被初始化。
  当调用getInstance() 方法时,内部类Holder类才得到初始化;Singleton实例属于静态的域,由虚拟机来保证它的线程安全。
  这个模式优势在于,getInstance()方法并没有被同步,只是执行一个域的访问,因为延时初始化并没有增加任何访问成本。

相关文章

网友评论

    本文标题: 单例模式和volatile关键字

    本文链接:https://www.haomeiwen.com/subject/mihauxtx.html