设计模式 | 单例模式

109 阅读1分钟

使用场景

  • 某种类型的对象具有全局唯一性,例如:Android 中的 Application 对象。
  • 避免产生多个对象消耗过多的资源,例如:访问 IO 等资源时。

Java 中的实现方式

  • 饿汉模式
public class Singleton {
    private static Singleton instance = new Singleton();
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        return instance;
    }
}

不能按需加载。

  • 懒汉模式
public class Singleton {
    private static Singleton instance;
    
    private Singleton() {}
    
    public static synchronized Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

同步开销较大。

  • Double Check Lock
public class Singleton {
    private static Singleton instance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if(instance == null) {
            synchronized(Singleton.class) {
                if(instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

DCL 失效问题:Java 5及其以上版本使用 volatile 关键字修饰 instance 解决。

  • 静态内部类
public class Singleton {
    private Singleton() {}
    
    public static Singleton getInstance() {
        return Instance.INSTANCE;
    }
    
    private static class Instance {
        private static final Singleton INSTANCE = new Singleton();
    }
}
  • 枚举
public enum Singleton {
    INSTANCE;
}

因为 Java 反序列化机制对枚举类的特殊处理,使得反序列化时不会重新创建对象。

  • 容器
public class SingletonManager {
    private static Map<String, Object> map = new HashMap();
    
    private SingletonManger() {}
    
    public static void putInstance(String key, Object instance) {
        if(!map.containsKey(key)) {
            map.put(key, instance);
        }
    }
    
    public static Object getInstance(String key) {
        return map.get(key);
    }
}

注意点

  • 防止反序列化时重新创建对象
public class Singleton implements Serializeable {
    private static final long serialVersionUID = 0L;
    private static Singleton instance = new Singleton();
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        return instance;
    }
    
    private Object readResolve() throws ObjectStreamException {
        return instance;
    }
}