什么是单例模式

  • 单例模式(Singleton Pattern)是一个比较简单的模式,实际应用很广泛,比如 Spring 中的Bean实例就是一个单例对象。
  • 定义:确保某一个类 只有一个实例,而且自行实例化并向整个系统提供这个实例。

单例模式的优缺点

  • 评价任何一种事务都要从两个方面去看,不能单一的评价。下面来看看单例模式有什么优缺点。

优点

  • 只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。
  • 单例模式可以避免对资源的多重占用,例如一个写文件动作,由于只有一个实例存在 内存中,避免对同一个资源文件的同时写操作。
  • 单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如可以设计一个单 例类,负责所有数据表的映射处理。

缺点

  • 单例模式一般没有接口,很难扩展(根据环境而定)。
  • 单例模式与单一职责原则有冲突。一个类应该只实现一个逻辑,而不关心是否是单例的。

单例模式的实现

  • 单例模式有很多的实现方式,但是各种实现的方式都有其优缺点,下面来看看各种的实现方式。
  • 单例模式的实现满足以下几点:
    • 构造方法私有。
    • 有一个静态方法获取该类的实例。
    • 该类保证只有一个实例。

懒汉式

  • 懒汉式是当用到这个对象的时候才会创建。
  • 优点:只有用到的时候才会创建这个对象,因此节省资源。
  • 简单的实现如下:
public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
  
    public static Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
}
复制代码
  • 上面的代码算是基本满足了单例模式,但是不能满足线程安全,一旦在多线程的环境下仍然是不能保证该类是单例的。
  • 如何保证线程安全,当然是加锁了,我们可以加线程同步锁synchronized,实现如下:
public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
    public static synchronized Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
}
复制代码
  • 此种实现方式虽然满足了线程安全,但是加锁势必会影响性能。

饿汉式

  • 饿汉式和懒汉式恰巧相反,在类加载的时候就创建实例。
  • 优点:还没用到就创建,浪费资源。
  • 缺点:在类加载的时候就创建,线程安全。
  • 实现如下:
public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
    return instance;  
    }  
}
复制代码

双重校验锁

  • 属于懒加载的一种实现方式,采用双重校验的机制,在多线程的情况仍然保持高性能。
  • 实现如下:
public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
        }  
    }  
    return singleton;  
    }  
}
复制代码

匿名内部类/静态内部类

  • 利用静态变量、静态代码块、静态方法都是在类加载的时候只加载一次的原理。
  • 实现如下:
public class Singleton {  
    private static class SingletonHolder {  
    private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
    return SingletonHolder.INSTANCE;  
    }  
}
复制代码

总结

  • 单例模式的实现虽然很简单,但是也要确保实现的性能和线程安全的问题。
  • 单例模式的实现主流的就是以上介绍的几种,分别是懒汉式线程不安全懒汉式线程安全饿汉式双重校验锁的实现静态内部类的实现。这几种方式各有优缺点,陈某推荐使用静态内部类的实现方式。
  • 单例模式也是Spring使用的一种设计模式,保证了Bean的单实例才能管理和监控Bean的创建和销毁。