跳至主要內容

单例设计模式

Dif大约 3 分钟软件设计设计模式

单例设计模式

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

1. 单例模式的结构

单例模式主要有以下角色:

  • 单例类。只能创建一个实例的类
  • 访问类。使用单例类

2. 单例模式的实现

单例设计模式分类两种:
饿汉式:类加载就会导致该单实例对象被创建 懒汉式:类加载不会导致该单实例对象被创建,而是首次使用该对象时才会被创建

2.1 饿汉式:

/**
 * 饿汉式
 * 在静态代码块中创建该类对象
 */
public class Singleton {
    // 私有构造方法
    private Singleton() {}
    
    // 在成员位置创建该类的对象
    private static Singleton instance;
    
    static {
        instance = new Singleton();
    }
    
    // 对外提供静态方法获取该对象
    public static Singleton getInstance() {
        return instance;
    }
}

饿汉式实现单例模式存在内存浪费的问题。

2.2 懒汉式-方式1(双重检查锁模式)

懒汉式实现单例模式在多线程情况下会有线程不安全的问题,以下示例使用双重检查锁模式实现。

/**
 * 双重检查模式
 */
public class Singleton {
    // 私有构造方法
    private Singleton() {}
    
    private static Singleton instance;
    
    // 对外提供静态方法获取该对象
    publice static Singleton getInstance() {
        // 第一次判断,如果instance不为null,不进入抢锁阶段,直接返回实例
        if(instance == null) {
            synchronized (Singleton.class) {
                // 第二次判断
                if(instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

双重检查锁模式是一种非常好的单例实现模式,解决例单例、性能、线程安全问题,但是在多线程情况下,可能会出现空指针问题,出现问题的原因是JVM在实例化对象的时候会进行优化和指令重排序操作。要解决双重检查锁模式带来空指针异常的问题,只需要使用volatile关键字修饰实例变量即可,volatile关键字可以保证可见性和有序性。

2.3 懒汉式-方式2(静态内部类方式)

静态内部类单例模式中实例由内部类创建,由于JVM在加载外部类过程中,是不会加载静态内部类的,只有内部类的属性/方法被调用时才会被加载,并初始化其静态属性。静态属性由于被static修饰,保证只被实例化一次,并且严格保证实例化顺序。

/**
 *静态内部类方式
 */
public class Singleton {
    // 私有构造方法
    private Singleton() {}
    
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    
    // 对外提供静态方法获取该对象
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}
\

第一次加载Singleton类时不会去初始化INSTANCE,只 有第一次调用getInstance,虚拟机加载SingletonHolder并初始化INSTANCE,这样不仅能确保线程安全,也能保证Singleton类的唯一性。\
静态内部类单例模式是一种优秀的单例模式,是开源项目中比较常见的一种单例模式。在没有加任何锁的情况下,保证了多线程下的安全,并且没有任何性能影响和空间的浪费。