一、单例模式是什么?
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
注意:
- 单例类只能有一个实例。
- 单例类必须自己创建自己的唯一实例。
- 单例类必须给所有其他对象提供这一实例。
适用场景:
- 需要生成唯一序列的环境
- 需要频繁实例化然后销毁的对象。
- 创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
- 方便资源相互通信的环境
二、模式分析
1.懒汉模式
代码案例
public class Singleton {
private static Singleton instance;
private Singleton (){
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
优点
实现起来比较简单,当类Singleton被加载的时候,静态变量static的instance未被创建并分配内存空间,当getInstance方法第一次被调用时,初始化instance变量,并分配内存,因此在某些特定条件下会节约了内存。
缺点
在多线程环境中,这种实现方法是完全错误的,根本不能保证单例的状态。
2.饿汉模式
代码案例
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
优点
实现起来简单,没有多线程同步问题。
缺点
当类Singleton被加载的时候,会初始化static的instance,静态变量被创建并分配内存空间,从这以后,这个static的instance对象便一直占着这段内存(即便你还没有用到这个实例),当类被卸载时,静态变量被摧毁,并释放所占有的内存,因此在某些特定条件下会耗费内存。
3.静态初始化
代码案例
public class Singleton {
private Singleton(){}
public static Singleton getInstance(){
return Inner.instance;
}
private static class Inner {
private static final Singleton instance = new Singleton();
}
}
优点
只有第一次调用getInstance方法时,虚拟机才加载 Inner 并初始化instance ,只有一个线程可以获得对象的初始化锁,其他线程无法进行初始化,保证对象的唯一性。目前此方式是所有单例模式中最推荐的模式。
4.双重锁模式
代码案例
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;
}
}
优点
线程安全,延迟初始化。这种方式采用双锁机制,安全且在多线程情况下能保持高性能
缺点
双重检查模式,进行了两次的判断,第一次是为了避免不要的实例,第二次是为了进行同步,避免多线程问题。由于singleton=new Singleton()对象的创建在JVM中可能会进行重排序,在多线程访问下存在风险,使用volatile修饰signleton实例变量有效,解决该问题。
5.枚举单例模式
代码案例
public enum Singleton {
INSTANCE;
//doSomething 该实例支持的行为
//可以省略此方法,通过Singleton.INSTANCE进行操作
public static Singleton getInstance() {
return Singleton.INSTANCE;
}
}
优点
默认枚举实例的创建是线程安全的,并且在任何情况下都是单例
枚举单例模式在《Effective Java》中推荐的单例模式之一。
缺点
常开发是很少使用的,就是很简单以导致可读性较差