写点什么

哇喔!20 种单例模式的实现与变异总结

作者:威哥爱编程
  • 2024-11-13
    北京
  • 本文字数:6376 字

    阅读完需:约 21 分钟

哇喔!20种单例模式的实现与变异总结

大家好,我是 V 哥。再聊到单例模式,你可能会说老掉牙的问题有啥值得讲的,可能还真有,笔试题上镜率极高的一道题还在考,你的回答如何能从网络上千遍一律的回答中脱颖而出,成为卷王,是不是得来点不一样的东西呢,这 20 种单例模式的实现与变异总结,也许可以让你有新的发现,收藏起来吧。


单例设计模式确保一个类在整个系统中只存在一个实例,通常用于全局访问的共享资源,如数据库连接、配置文件读取、线程池等。以下 V 哥总结的 20 种不同的实现,来看一下:

1. 饿汉式(Eager Initialization)

  • 实现:在类加载时就创建单例实例,使用finalstatic关键字定义。

  • 特点:线程安全;类加载时实例即创建,可能会导致不必要的内存占用。


public class SingletonEager {    private static final SingletonEager instance = new SingletonEager();    private SingletonEager() {}    public static SingletonEager getInstance() {        return instance;    }}
复制代码

2. 懒汉式(Lazy Initialization)

  • 实现:在首次使用时才创建实例。

  • 特点:延迟加载,节省资源;不是线程安全的,适合单线程环境。


public class SingletonLazy {    private static SingletonLazy instance;    private SingletonLazy() {}    public static SingletonLazy getInstance() {        if (instance == null) {            instance = new SingletonLazy();        }        return instance;    }}
复制代码

3. 线程安全的懒汉式(Synchronized Lazy Initialization)

  • 实现:在懒汉式基础上加入sychronized关键字,确保多线程环境的安全。

  • 特点:线程安全,但加锁会影响性能。


public class SingletonLazySync {    private static SingletonLazySync instance;    private SingletonLazySync() {}    public static synchronized SingletonLazySync getInstance() {        if (instance == null) {            instance = new SingletonLazySync();        }        return instance;    }}
复制代码

4. 双重检查锁(Double-Checked Locking)

  • 实现:在获取实例时先判断是否为空,再加锁创建实例。

  • 特点:在多线程情况下性能更高,线程安全;适合多线程环境。


public class SingletonDCL {    private static volatile SingletonDCL instance;    private SingletonDCL() {}    public static SingletonDCL getInstance() {        if (instance == null) {            synchronized (SingletonDCL.class) {                if (instance == null) {                    instance = new SingletonDCL();                }            }        }        return instance;    }}
复制代码

5. 静态内部类(Static Inner Class)

  • 实现:利用类加载机制,延迟创建实例。

  • 特点:线程安全,懒加载,效率高。


public class SingletonInnerClass {    private SingletonInnerClass() {}    private static class Holder {        private static final SingletonInnerClass INSTANCE = new SingletonInnerClass();    }    public static SingletonInnerClass getInstance() {        return Holder.INSTANCE;    }}
复制代码

6. 枚举单例(Enum Singleton)

  • 实现:使用枚举类型实现单例,JVM 保证了线程安全。

  • 特点:线程安全、防止反射和序列化破坏单例,是最佳实现方式之一。


public enum SingletonEnum {    INSTANCE;    public void someMethod() {        // some code    }}
复制代码

7. 使用容器实现单例(Container Singleton)

  • 实现:使用容器(如 Map)存储类对象。

  • 特点:适合管理多种类型的单例;实现复杂度增加,使用场景较特殊。


import java.util.HashMap;import java.util.Map;
public class SingletonContainer { private static Map<String, Object> instanceMap = new HashMap<>(); private SingletonContainer() {} public static void registerInstance(String key, Object instance) { if (!instanceMap.containsKey(key)) { instanceMap.put(key, instance); } } public static Object getInstance(String key) { return instanceMap.get(key); }}
复制代码


除了常见的 7 种实现方式,还有几种不同的单例模式变体,适合更复杂的使用场景:

8. 线程本地单例(ThreadLocal Singleton)

  • 实现:使用ThreadLocal变量保证每个线程有自己的单例实例。

  • 特点:每个线程会有一个单例实例,不同线程之间的实例是独立的;适合线程隔离的数据,如数据库连接或特定线程的上下文信息。


public class SingletonThreadLocal {    private static final ThreadLocal<SingletonThreadLocal> threadLocalInstance =            ThreadLocal.withInitial(SingletonThreadLocal::new);
private SingletonThreadLocal() {}
public static SingletonThreadLocal getInstance() { return threadLocalInstance.get(); }}
复制代码

9. CAS 实现的单例(CAS-based Singleton)

  • 实现:利用java.util.concurrent.atomic.AtomicReference原子类实现无锁单例。

  • 特点:通过 CAS 保证线程安全,性能较高;适合高并发场景,但代码稍复杂。


import java.util.concurrent.atomic.AtomicReference;
public class SingletonCAS { private static final AtomicReference<SingletonCAS> INSTANCE = new AtomicReference<>();
private SingletonCAS() {}
public static SingletonCAS getInstance() { while (true) { SingletonCAS current = INSTANCE.get(); if (current != null) { return current; } current = new SingletonCAS(); if (INSTANCE.compareAndSet(null, current)) { return current; } } }}
复制代码

10. 枚举双重锁单例(Enum Holder with DCL)

  • 实现:结合Enum的延迟加载特性与双重检查锁来实现。

  • 特点:利用Enum保证单例的序列化安全,结合 DCL 提高性能。适合对高性能和安全性要求极高的场景。


public class SingletonEnumDCL {    private SingletonEnumDCL() {}
private enum Holder { INSTANCE; private final SingletonEnumDCL instance = new SingletonEnumDCL(); }
public static SingletonEnumDCL getInstance() { return Holder.INSTANCE.instance; }}
复制代码

11. 注册表式单例(Registry Singleton)

  • 实现:通过注册表(如HashMap)集中管理多个不同类型的单例实例。

  • 特点:适合多单例实例的场景,类似于容器模式;复杂性较高,适合复杂的依赖管理系统。


import java.util.Map;import java.util.concurrent.ConcurrentHashMap;
public class SingletonRegistry { private static final Map<String, Object> registry = new ConcurrentHashMap<>();
private SingletonRegistry() {}
public static void registerSingleton(String key, Object instance) { registry.putIfAbsent(key, instance); }
public static Object getSingleton(String key) { return registry.get(key); }}
复制代码

12. Bill Pugh 单例(Bill Pugh Singleton)

  • 实现:通过静态内部类加载实例。

  • 特点:一种特殊的静态内部类实现,解决了饿汉式和懒汉式的缺点;线程安全、高效、延迟加载。


public class SingletonBillPugh {    private SingletonBillPugh() {}
private static class SingletonHelper { private static final SingletonBillPugh INSTANCE = new SingletonBillPugh(); }
public static SingletonBillPugh getInstance() { return SingletonHelper.INSTANCE; }}
复制代码

13. 反射防护单例(Reflection Proof Singleton)

  • 实现:通过枚举或特殊处理反射的方式来防止反射破坏单例。

  • 特点:保护单例不被反射攻击破坏,适合安全性要求较高的场景。


public class SingletonReflectionProof {    private static final SingletonReflectionProof INSTANCE = new SingletonReflectionProof();
private SingletonReflectionProof() { if (INSTANCE != null) { throw new IllegalStateException("Instance already created!"); } }
public static SingletonReflectionProof getInstance() { return INSTANCE; }}
复制代码

14. 资源管理单例(Resource Management Singleton)

  • 实现:在类的finalize方法中释放资源或做额外处理。

  • 特点:确保系统资源不会被过多实例浪费,适合资源有限的情况。


public class SingletonResource {    private static final SingletonResource INSTANCE = new SingletonResource();        private SingletonResource() {        // 初始化资源    }
public static SingletonResource getInstance() { return INSTANCE; }
@Override protected void finalize() throws Throwable { super.finalize(); // 释放资源 }}
复制代码


除了以上列出的常见单例模式实现方式,还有一些变种实现和特殊情况的单例设计。

下面介绍一些更高级的实现方式

15. 接口代理单例(Interface Proxy Singleton)

  • 实现:通过动态代理生成单例实例,控制对单例对象的访问。

  • 特点:适用于复杂的业务场景,可以在代理中加入权限控制、日志等额外逻辑。


import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;
public class SingletonProxy { private static final MySingletonInterface INSTANCE = (MySingletonInterface) Proxy.newProxyInstance( MySingletonInterface.class.getClassLoader(), new Class[]{MySingletonInterface.class}, new SingletonHandler(new MySingleton()) );
private SingletonProxy() {}
public static MySingletonInterface getInstance() { return INSTANCE; }
private static class SingletonHandler implements InvocationHandler { private final MySingleton instance;
public SingletonHandler(MySingleton instance) { this.instance = instance; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 可以在这里加入权限控制、日志等 return method.invoke(instance, args); } }}
interface MySingletonInterface { void doSomething();}
class MySingleton implements MySingletonInterface { @Override public void doSomething() { System.out.println("Doing something..."); }}
复制代码

16. Service Locator 单例(Service Locator Singleton)

  • 实现:Service Locator 模式是一种设计模式,通过注册中心管理单例对象,避免直接依赖实例,便于松耦合和模块化。

  • 特点:更适合用于依赖注入和模块间解耦场景,适用于复杂系统中的组件管理。


import java.util.HashMap;import java.util.Map;
public class ServiceLocator { private static final Map<Class<?>, Object> services = new HashMap<>();
private ServiceLocator() {}
public static <T> void registerService(Class<T> serviceClass, T instance) { services.put(serviceClass, instance); }
@SuppressWarnings("unchecked") public static <T> T getService(Class<T> serviceClass) { return (T) services.get(serviceClass); }}
复制代码

17. 对象池单例(Object Pool Singleton)

  • 实现:使用对象池模式,创建有限数量的单例对象,并在对象使用完毕后进行复用。

  • 特点:在需要复用固定数量资源时非常有效,如数据库连接池、线程池等。


import java.util.Queue;import java.util.concurrent.ConcurrentLinkedQueue;
public class SingletonObjectPool { private static final int POOL_SIZE = 5; private static final Queue<SingletonObjectPool> pool = new ConcurrentLinkedQueue<>();
static { for (int i = 0; i < POOL_SIZE; i++) { pool.add(new SingletonObjectPool()); } }
private SingletonObjectPool() {}
public static SingletonObjectPool getInstance() { SingletonObjectPool instance = pool.poll(); if (instance == null) { instance = new SingletonObjectPool(); } return instance; }
public void release() { pool.offer(this); }}
复制代码

18. 克隆防御单例(Clone-Proof Singleton)

  • 实现:通过覆盖clone方法,防止克隆破坏单例模式。

  • 特点:保证单例对象无法通过克隆创建额外实例,防止了反射破坏单例的风险。


public class SingletonCloneProof implements Cloneable {    private static final SingletonCloneProof INSTANCE = new SingletonCloneProof();
private SingletonCloneProof() {}
public static SingletonCloneProof getInstance() { return INSTANCE; }
@Override protected Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException("Cannot clone singleton instance"); }}
复制代码

19. 定时刷新单例(Time-Based Singleton Refresh)

  • 实现:在指定时间或条件下重新创建单例对象,通常用于缓存或短期需要重新加载的对象。

  • 特点:适合数据或配置需要定期更新的情况,确保每个时间段获得最新的单例实例。


public class SingletonTimeBased {    private static SingletonTimeBased instance;    private static long lastCreatedTime = System.currentTimeMillis();    private static final long REFRESH_INTERVAL = 30000; // 30 seconds
private SingletonTimeBased() {}
public static synchronized SingletonTimeBased getInstance() { if (instance == null || System.currentTimeMillis() - lastCreatedTime > REFRESH_INTERVAL) { instance = new SingletonTimeBased(); lastCreatedTime = System.currentTimeMillis(); } return instance; }}
复制代码

20. 弱引用单例(Weak Reference Singleton)

  • 实现:使用WeakReference包装单例对象,允许 Java 垃圾收集器在内存不足时回收该对象。

  • 特点:适合内存敏感的场景,减少长时间未使用对象的内存占用,但对象可能会在不经意间被 GC 回收。


import java.lang.ref.WeakReference;
public class SingletonWeakReference { private static WeakReference<SingletonWeakReference> instanceRef;
private SingletonWeakReference() {}
public static synchronized SingletonWeakReference getInstance() { SingletonWeakReference instance = (instanceRef == null) ? null : instanceRef.get(); if (instance == null) { instance = new SingletonWeakReference(); instanceRef = new WeakReference<>(instance); } return instance; }}
复制代码

最后

这些变种和扩展可以用来应对不同的使用场景,从安全性到性能需求再到资源管理需求。根据特定需求,可以选择或定制合适的单例实现方式。关注威哥爱编程,编程乐无边。

发布于: 刚刚阅读数: 4
用户头像

华为 HDE、CSDN 博客专家、Java畅销书作者 2018-05-30 加入

全栈领域优质创作者(Java/HarmonyOS/AI),公众号:威哥爱编程

评论

发布
暂无评论
哇喔!20种单例模式的实现与变异总结_Java_威哥爱编程_InfoQ写作社区