单例模式

来源:互联网 发布:淘宝评价中心 编辑:程序博客网 时间:2024/04/28 01:47

注意点

  • 单例类只能有一个实例
  • 单例类必须自己创建自己的唯一实例
  • 单例类必须给所有其他对象提供这一实例

优点

  • 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例
  • 避免对资源的多重占用

缺点

  • 没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化

懒汉、线程不安全(不支持线程安全)

  • 描述:
    • 这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁synchronized,所以严格意义上它并不算单例模式
public class Singleton {    private static Singleton singleton;    //让构造函数为 private,这样该类就不会被实例化    private Singleton() {    }    //获取唯一可用的对象    public static Singleton getInstance(){        if (singleton == null) {            singleton = new Singleton();        }        return singleton;    }    public void TestSingleton() {        System.out.println("单例模式-懒汉、线程不安全");    }}
public class SingletonDemo {    public static void main(String[] args) {        //不合法的构造函数        //编译时错误:构造函数 SingleObject() 是不可见的        //SingleObject object = new SingleObject();        //获取唯一可用的对象        Singleton singleton = Singleton.getInstance();        singleton.TestSingleton();    }}

懒汉、线程安全

  • 描述:
    • 这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步
  • 优点:
    • 第一次调用才初始化,避免内存浪费
  • 缺点:
    • 必须加锁 synchronized 才能保证单例,但加锁会影响效率
  • getInstance() 的性能对应用程序不是很关键(该方法使用不太频繁)
public class SingletonSafety {    private SingletonSafety(){}    private static SingletonSafety singletonSafety;    public static synchronized SingletonSafety getInstance(){        if (singletonSafety == null) {            singletonSafety = new SingletonSafety();        }        return singletonSafety;    }    public void TestSingletonSafety() {        System.out.println("单例模式-懒汉、线程安全");    }}

饿汉

  • 描述:
    • 这种方式比较常用,但容易产生垃圾对象
  • 优点:
    • 没有加锁,执行效率会提高
  • 缺点:
    • 类加载时就初始化,浪费内存
public class SingletonHungry {    private SingletonHungry() {}    private static SingletonHungry singletonHungry = new SingletonHungry();    public static SingletonHungry getInstance() {        return singletonHungry;    }    public void TestSingletonHungry() {        System.out.println("单例模式-饿汉");    }}

双检锁/双重校验锁(DCL,即 double-checked locking)

  • 描述
    • 这种方式采用双锁机制,安全且在多线程情况下能保持高性
  • getInstance() 的性能对应用程序很关键
public class SingletonDCL {    private SingletonDCL(){}    private volatile static SingletonDCL singletonDCL;    public static SingletonDCL getInstance() {        if (singletonDCL == null) {            synchronized (SingletonDCL.class) {                if (singletonDCL == null) {                    singletonDCL = new SingletonDCL();                }            }        }        return singletonDCL;    }    public void TestSingletonDCL() {        System.out.println("单例模式-双检锁/双重校验锁(DCL,即 double-checked locking)");    }}

登记式/静态内部类

  • 描述:
    • 这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。
public class SingletonStatic {    private SingletonStatic() {}    private static class SingletonHolder{        private static final SingletonStatic SINGLETON_STATIC = new SingletonStatic();    }    public static final SingletonStatic getInstance() {        return SingletonHolder.SINGLETON_STATIC;    }    public void TestSingletonStatic() {        System.out.println("单例模式-登记式/静态内部类");    }}