引言

单例模式(Singleton Pattern)是属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

应用场景

  • 要求生产唯一序列号。
  • WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
  • 创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
  • 为了保证资源不被浪费,所以使用单例创建一次对象,然后后面就可以不用创建对象了。

优缺点

  • 优点:在内存中只有一个对象,节省内存空间。避免频繁的创建销毁对象,可以提高性能。避免对共享资源的多重占用。可以全局访问。
  • 缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

Java 代码

饿汉

在虚拟机加载该类时就直接完成变量的初始化,没有线程安全问题,但是没有懒加载

  1. public class Singleton {
  2. private static Singleton instance = new Singleton();
  3. private Singleton() { }
  4. public static Singleton getInstance() {
  5. return instance;
  6. }
  7. }

懒汉

懒加载,线程不安全,可能多线程同时调用getInstance方法导致一个线程维护一个Singleton实例

  1. public class Singleton {
  2. private static Singleton instance;
  3. private Singleton (){
  4. }
  5. public static Singleton getInstance() {
  6. if (instance == null) {
  7. instance = new Singleton();
  8. }
  9. return instance;
  10. }
  11. }

线程安全

synchronized 在JDK1.6之前是重量级锁,涉及到系统调用,所以性能较差,但是在JDK1.6之后有优化(CAS + AQS),所以性能会好点。

  1. public class Singleton {
  2. private static Singleton instance;
  3. private Singleton (){
  4. }
  5. public static synchronized Singleton getInstance() {
  6. if (instance == null) {
  7. instance = new Singleton();
  8. }
  9. return instance;
  10. }
  11. }

静态内部

通过静态内部类持有一个实例,实现线程安全和饿汉原理一样,不过因为静态内部类使用到才加载,所以起到了延迟加载的作用。

public class Singleton {
    private Singleton() {
    }

    private static Singleton instance;

    public static synchronized Singleton getInstance() {
        return SingletonHolder.instance;
    }
    static private class SingletonHolder{
        private static final Singleton instance = new Singleton();
    }
}

枚举

线程安全速度快,但是可读性较差。

public enum Singleton {  
     INSTANCE;  
     public void otherMethod() {  }  
 }

双重检查

public class Singleton {
    private Singleton() {
    }

    private volatile static Singleton instance;

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}