设计模式 - 单例模式(懒汉式、饿汉式、静态内部类、枚举)

目录

一、单例模式的核心概念

二、实现单例模式的方法

[2.1 懒汉式(Lazy Initialization)](#2.1 懒汉式(Lazy Initialization))

[2.1.1 线程不安全版本](#2.1.1 线程不安全版本)

[2.1.2 双重检查锁定(线程安全)](#2.1.2 双重检查锁定(线程安全))

[2.2 饿汉式(Eager Initialization)](#2.2 饿汉式(Eager Initialization))

[2.3 静态内部类(Static Inner Class)](#2.3 静态内部类(Static Inner Class))

[2.4 枚举(Enum)](#2.4 枚举(Enum))

三、单例模式的优缺点

优点

缺点

四、总结


设计模式是在软件设计中为解决特定问题而反复出现的解决方案的描述。它们不是完成任务的具体代码,而是模板或蓝图,指导开发者如何有效地解决问题。设计模式通常涉及类的行为和交互方式,它们可以帮助开发者编写可维护、可扩展和可复用的代码。

单例模式是一种常用的软件设计模式,旨在确保一个类只有一个实例,并提供一个全局访问点来访问这个实例。这种模式在很多场景下都非常有用,特别是在需要对资源进行集中管理和控制的情况下。

一、单例模式的核心概念

单例模式的核心在于两个方面:

  1. 确保类只有一个实例:通过某种机制来防止多次实例化同一个类。
  2. 提供一个全局访问点:使得应用程序中的任何部分都可以访问到这个唯一的实例。

二、实现单例模式的方法

2.1 懒汉式(Lazy Initialization)

懒汉式单例模式会在第一次调用getInstance方法时才创建实例。

2.1.1 线程不安全版本

java 复制代码
public class LazySingleton {
    private static LazySingleton instance;

    private LazySingleton() {}

    public static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

2.1.2 双重检查锁定(线程安全)

为了使其线程安全,可以采用同步方法或者双重检查锁定(Double Checked Locking):

java 复制代码
public class LazySingletonThreadSafe {
    // 使用volatile关键字保证可见性和有序性
    private volatile static LazySingletonThreadSafe uniqueInstance;  

    private LazySingletonThreadSafe() {
        // 防止反射攻击
        if (uniqueInstance != null) {
            throw new IllegalStateException("Singleton instance already created!");
        }
    }

    public static LazySingletonThreadSafe getInstance() {
        if (uniqueInstance == null) { // 第一次检查
            synchronized(LazySingletonThreadSafe.class) {
                if (uniqueInstance == null) { // 第二次检查
                    uniqueInstance = new LazySingletonThreadSafe();
                }
            }
        }
        return uniqueInstance;
    }
}

2.2 饿汉式(Eager Initialization)

饿汉式单例模式在类加载的时候就创建了实例,因此没有线程安全问题。

java 复制代码
public class EagerSingleton {
    private static final EagerSingleton instance = new EagerSingleton();

    private EagerSingleton() {}

    public static EagerSingleton getInstance() {
        return instance;
    }
}

2.3 静态内部类(Static Inner Class)

这种方式结合了懒汉式和饿汉式的优点,实现了线程安全并且只有在第一次调用getInstance方法时才会初始化。

java 复制代码
public class StaticInnerSingleton {
    private StaticInnerSingleton() {}

    private static class SingletonHolder {
        private static final StaticInnerSingleton INSTANCE = new StaticInnerSingleton();
    }

    public static StaticInnerSingleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

2.4 枚举(Enum)

枚举可以用来实现单例模式,这是《Effective Java》推荐的方式之一,简洁且线程安全。

java 复制代码
public enum EnumSingleton {
    INSTANCE;

    public void someMethod() {
        // 实现代码
    }
}

三、单例模式的优缺点

优点

  1. 节省资源:因为单例模式只允许一个实例存在,所以在内存使用上比较经济。
  2. 简化访问:提供全局访问点,方便在任何地方获取实例。
  3. 易于扩展:可以很容易地扩展原有的功能而不影响其他模块。

缺点

  1. 难以测试:单例模式破坏了对象的封闭性,使得在单元测试时很难模拟单例的行为。
  2. 违反单一职责原则:单例类通常承担了过多的责任。
  3. 潜在的并发问题:在多线程环境下需要特别注意线程安全问题。

四、总结

单例模式是一种非常实用的设计模式,尤其适用于那些需要频繁访问且创建成本较高的对象。

然而,在使用单例模式时也需要谨慎,因为它可能会引入一些设计上的问题,特别是当单例类变得过于庞大时。

在现代软件架构中,依赖注入(DI)框架(如Spring)的使用越来越广泛,它提供了一种更加灵活的方式来管理对象的生命周期,因此在很多情况下,单例模式可以通过依赖注入来实现,而不是手动实现。

因为:Spring框架本身就提供了依赖注入(Dependency Injection, DI)机制来管理bean的生命周期,并且默认情况下bean是以单例(Singleton)模式存在的。这意味着,对于大多数场景来说,你只需要声明一个类,并通过适当的注解(如@Service@Repository@Controller等)标记它,Spring容器就会为你管理这个bean的实例化和生命周期。对于同一个bean类型,Spring容器只会创建一个实例,并且每次请求该bean时都会返回相同的实例。

相关推荐
jonyleek10 分钟前
数据可视化:JVS-BI仪表盘图表样式配置全攻略,打造个性化数据展示!
java·大数据·信息可视化·数据挖掘·数据分析·自动化·软件需求
WangMing_X10 分钟前
C# 单个函数实现各进制数间转换
java·开发语言·算法·c#·winform·软件
南宫生24 分钟前
贪心算法理论基础和习题【算法学习day.17】
java·学习·算法·leetcode·链表·贪心算法
jc0803kevin29 分钟前
solidity的struct对象,web3j java解析输出参数
java·web3·solidity
勇敢滴勇33 分钟前
【C++】继承和多态常见的面试问题
java·c++·面试
nice6666037 分钟前
初识JDBC
java·数据库·sql·mysql·idea
计算机学姐39 分钟前
基于SpringBoot的汽车票网上预订系统
java·vue.js·spring boot·后端·mysql·java-ee·mybatis
screamn44 分钟前
Sentinel详解
java·sentinel
哎呦没1 小时前
农村扶贫管理:SpringBoot解决方案
java·spring boot·后端
只看见而已1 小时前
锁升级及线程池相关
java·开发语言