单例模式深度剖析:各种实现方式的优缺点对比

发布时间:2026/9/7 11:09:16
单例模式深度剖析:各种实现方式的优缺点对比 目录一、单例模式的定义和应用场景一定义及基本要点二应用场景二、饿汉式单例模式一基本代码展示分析二基本分析和建议三、懒汉式单例模式双重检查锁一基本代码展示分析二基本分析和建议四、静态内部类实现单例模式一基本代码展示分析二基本分析和建议五、注册式单例模式一枚举式单例模式代码及分析Effective Java推荐单例模式二容器式单例模式代码及分析适用于实例非常多的情况便于管理但是是非线程安全的六、总结参考书籍、文献和资料干货分享感谢您的阅读在软件设计中单例模式是一种极为常见且重要的设计模式它确保一个类只有一个实例并提供全局访问点。这一特性使得单例模式在很多场景下都能有效地保证资源的统一管理和减少内存的浪费尤其在诸如数据库连接池、线程池等资源管理的应用中发挥着至关重要的作用。然而尽管单例模式非常实用它的实现方式却并非一成不变。在不同的应用场景下我们可能需要根据实际需求选择不同的单例实现策略——从简单的饿汉式单例到需要懒加载的懒汉式再到结合了性能优化的静态内部类实现每种实现方式都有其优缺点适用于不同的情况。本篇文章将深入分析Java中的多种单例模式实现帮助你了解它们的优缺点并通过实际代码示例展示如何在实际项目中合理选择和应用这些模式。无论你是初学者还是有一定经验的开发者相信你都能从中找到提升代码设计质量和性能的宝贵经验。一、单例模式的定义和应用场景一定义及基本要点单例模式是指确保一个类在任何情况下都绝对只有一个实例并提供一个全局访问点。该模式有三个基本要点一是这个类只能有一个实例二是它必须自行创建这个实例三是它必须自行向整个系统提供这个实例。二应用场景应用场景J2EE中的ServlertContext、SerletContextConfig等、Spring框架应用中的ApplicationContext、数据库连接池等。二、饿汉式单例模式一基本代码展示分析/** * 描述饿汉式单例模式 * 优点没有任何锁执行效率高用户体验比懒汉式单例模式更好 * 缺点类加载的时候就初始化不管用不用都占内存空间 * 建议适用于单例模式较少的场景 * 如果我们在程序启动后一定会加载到类那么用饿汉模式实现的单例简单又实用 * 如果我们是写一些工具类则优先考虑使用懒汉模式可以避免提前被加载到内存中占用系统资源。 * * author yanfengzhang * date 2020-01-02 20:39 */ public class HungrySingleton { private final static HungrySingleton HUNGRY_SINGLETON new HungrySingleton(); private HungrySingleton() { } public static HungrySingleton getInstance() { return HUNGRY_SINGLETON; } }二基本分析和建议优点没有任何锁执行效率高用户体验比懒汉式单例模式更好缺点类加载的时候就初始化不管用不用都占内存空间建议适用于单例模式较少的场景如果我们在程序启动后一定会加载到类那么用饿汉模式实现的单例简单又实用如果我们是写一些工具类则优先考虑使用懒汉模式可以避免提前被加载到内存中占用系统资源。三、懒汉式单例模式双重检查锁一基本代码展示分析/** * 描述懒汉式单例模式---双重检查锁 * 相比单锁而言双重检查锁性能上虽然有提升但是依旧用到了synchronized关键字总归要上锁对程序性能还是存在一定的性能影响 * 不算最优--存在优化空间 * * 建议如果我们在程序启动后一定会加载到类那么用饿汉模式实现的单例简单又实用 * 如果我们是写一些工具类则优先考虑使用懒汉模式可以避免提前被加载到内存中占用系统资源。 * * author yanfengzhang * date 2020-01-02 20:53 */ public class LazyDoubleCheckSingleton { /** * volatile 关键字可以保证线程间变量的可见性还有一个作用就是阻止局部重排序的发生 */ private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton null; private LazyDoubleCheckSingleton() { } public static LazyDoubleCheckSingleton getInstance() { if (null lazyDoubleCheckSingleton) { synchronized (LazyDoubleCheckSingleton.class) { if (null lazyDoubleCheckSingleton) { lazyDoubleCheckSingleton new LazyDoubleCheckSingleton(); } } } return lazyDoubleCheckSingleton; } }二基本分析和建议相比单锁而言双重检查锁性能上虽然有提升但是依旧用到了synchronized关键字总归要上锁对程序性能还是存在一定的性能影响。注意里面volatile的使用建议如果我们在程序启动后一定会加载到类那么用饿汉模式实现的单例简单又实用如果我们是写一些工具类则优先考虑使用懒汉模式可以避免提前被加载到内存中占用系统资源。四、静态内部类实现单例模式一基本代码展示分析/** * 描述屏蔽饿汉式单例模式的内存浪费问题和双重检查锁中synchronized的性能问题 * 避免因为反射破坏单例 * * author yanfengzhang * date 2020-01-02 21:08 */ public class LazyInnerClassSingleton { /** * 使用LazyInnerClassSingleton的时候会先默认初始化换内部类 * 如果没有使用则内部类是不加载的 */ private LazyInnerClassSingleton() { /*为了避免反射破坏单例需要在构造方法中增加限制一旦出现多次重复创建直接抛出异常*/ if (null ! Lazyholder.LAZY_INNER_CLASS_SINGLETON) { throw new RuntimeException(创建LazyInnerClassSingleton异常不允许创建多个实例); } } /** * 每一个关键字都不是多余的static是为了使单例的空间共享保证这个方法不会被重写、重载 */ public static final LazyInnerClassSingleton getInstance() { /*在返回结果前一定会先加载内部类*/ return Lazyholder.LAZY_INNER_CLASS_SINGLETON; } /** * 默认不加载 */ private static class Lazyholder { private static final LazyInnerClassSingleton LAZY_INNER_CLASS_SINGLETON new LazyInnerClassSingleton(); } }二基本分析和建议屏蔽饿汉式单例模式的内存浪费问题和双重检查锁中synchronized的性能问题同时考虑避免因为反射破坏单例问题。相对而言性能最好五、注册式单例模式注册式单例模式/登记式单例模式将每个实例都登记到一个地方使用唯一的标识获取单例。注册单例模式有两种枚举式单例模式容器式单例模式一枚举式单例模式代码及分析Effective Java推荐单例模式/** * 描述注册式单例模式/登记式单例模式将每个实例都登记到一个地方使用唯一的标识获取单例。 * 注册单例模式有两种枚举式单例模式容器式单例模式 * 此为枚举式单例模式---Effective Java推荐单例模式 * * author yanfengzhang * date 2020-01-03 09:59 */ public enum EnumSingleton { /*枚举式单例模式*/ INSTANCE; private Object data; public Object getData() { return data; } public void setData(Object data) { this.data data; } public static EnumSingleton getInstance() { return INSTANCE; } }二容器式单例模式代码及分析适用于实例非常多的情况便于管理但是是非线程安全的/** * 描述注册式单例模式/登记式单例模式将每个实例都登记到一个地方使用唯一的标识获取单例。 * 注册单例模式有两种枚举式单例模式容器式单例模式 * 建议容器式单例模式适用于实例非常多的情况便于管理但是是非线程安全的。 * * author yanfengzhang * date 2020-01-03 10:51 */ public class ContainerSingleton { private ContainerSingleton() { } private static MapString, Object ioc new ConcurrentHashMap(); public static Object getBean(String className) { synchronized (ioc) { if (ioc.containsKey(className)) { return ioc.get(className); } Object obj null; try { obj Class.forName(className).newInstance(); ioc.put(className, obj); } catch (Exception e) { e.printStackTrace(); } return obj; } } }六、总结单例模式作为一种经典的设计模式在软件开发中扮演着重要的角色。它不仅能够保证系统中某一资源的唯一性还能提供全局访问点使得系统的资源管理更加高效和可靠。本文介绍了多种单例模式的实现方式包括饿汉式单例、懒汉式单例双重检查锁、静态内部类实现单例以及注册式单例模式枚举和容器式并对每种方式的优缺点进行了详细分析。在实际应用中选择合适的单例实现方式至关重要。如果你的应用程序中单例类的初始化开销较小且始终需要加载饿汉式单例可能是一个简单且高效的选择而在需要延迟初始化的场景下懒汉式单例或者静态内部类实现则能更好地节省资源。对于实例管理复杂的应用注册式单例模式通过枚举和容器化的方式提供了灵活的解决方案。尽管每种实现方式都有其优缺点开发者应根据具体的需求、性能要求以及系统的复杂度来选择合适的模式。通过理解和掌握单例模式的实现你不仅能提升程序的结构设计还能在实际开发中避免常见的资源浪费和性能瓶颈。希望本文的分析和代码示例能够帮助你更好地理解和应用单例模式提升你的编程技能和系统设计能力。参考书籍、文献和资料1.《Sring 5 核心原理与30个类手写实战》谭勇徳中国公信出版社2019.2.极客时间课程《Java性能调优实战》刘超2019.