单例模式

来源:互联网 发布:java 汉字转英文缩写 编辑:程序博客网 时间:2024/06/08 19:16

饿汉式(常用)

public class EagerSingleton {
    private static EagerSingleton instance = new EagerSingleton();
    /**
     * 私有默认构造子
     */
    private EagerSingleton(){}
    /**
     * 静态工厂方法
     */
    public static EagerSingleton getInstance(){
        return instance;
    }
}

懒汉式

public class LazySingleton {
    private static LazySingleton instance = null;
    /**
     * 私有默认构造子
     */
    private LazySingleton(){}
    /**
     * 静态工厂方法
     */
    public static synchronized LazySingleton getInstance(){
        if(instance == null){
            instance = new LazySingleton();
        }
        return instance;
    }
}

简单总结一下这样的写法:

  1. 提供一个全局静态的getIns方法,使得易于使用.
  2. 延迟Singleton的实例化,节省资源(所谓的懒汉式).
  3. 缺点是线程不安全.当多个线程同时进入if (null == ins) {}的时候就会创建多个实例.


饿汉式与之前提到的懒汉式不同,它在我们调用getIns之前就实例化了(在类加载的时候就实例化了),所以不是一个懒加载,这样就有几个缺点:

  1. 延长了类加载时间
  2. 如果没用到这个类,就浪费了资源(加载了但是没用它)
  3. 不能传递参数(很显然适用的场景会减少)

性能进阶

接下去介绍一种更优秀的,线程安全的单例写法---双重检查锁模式(double check locking pattern)

public class DoubleCheck {    private volatile static DoubleCheck ins;    private DoubleCheck() {}    public static DoubleCheck getIns() {        if (null==ins){ //检查            synchronized (DoubleCheck.class){                if (null == ins) { //又检查一次                    ins = new DoubleCheck();                }            }        }        return ins;    }}

注意这里的ins用了volatile关键字来修饰,为什么呢?
因为执行ins = new DoubleCheck()做了很多事情:

  1. 给ins分配内存
  2. 调用构造函数来初始化成员变量(可能会很久)
  3. 将ins对象指向分配的内存空间(执行完这步 ins才不为null)

静态内部类

静态内部类原理同上,另外虽然它看上去有点恶汉式,但是与之前的恶汉有点不同,它在类Singleton加载完毕后并没有实例化,而是当调用getIns去加载Holder的时候才会实例化,静态内部类的方式把实例化延迟到了内部类的加载中去了!所以它比饿汉式更优秀!(偷偷告诉你Effective Java中也推荐这个方式)

例子:

public class Singleton {    private static class Holder{        private static final Singleton INSTANCE = new Singleton();    }    public static Singleton getIns(){        return Holder.INSTANCE;    }}
推荐双重检查锁和静态内部类

1 0