Java一分钟之-设计模式:单例模式的实现

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
可观测可视化 Grafana 版,10个用户账号 1个月
简介: 【5月更文挑战第16天】本文介绍了单例模式的四种实现方式:饿汉式(静态初始化)、懒汉式(双检锁)、静态内部类和枚举单例,以及相关问题和解决方法。关注线程安全、反射攻击、序列化、生命周期和测试性,选择合适的实现方式以确保代码质量。了解单例模式的优缺点,谨慎使用,提升设计效率。

单例模式是一种常见的设计模式,用于确保一个类只有一个实例,并提供全局访问点。本文将介绍单例模式的几种实现方式,以及相关的常见问题、易错点和如何避免它们。
image.png

1. 饿汉式(Static Singleton)

在类加载时就创建实例,线程安全,但可能导致不必要的资源浪费。

public class Singleton {
   
   
    private static final Singleton INSTANCE = new Singleton();

    private Singleton() {
   
   }

    public static Singleton getInstance() {
   
   
        return INSTANCE;
    }
}

2. 懒汉式(DCL,Double-Checked Locking)

延迟初始化,只有在首次使用时才创建实例。使用volatile关键字保证可见性和有序性。

public class Singleton {
   
   
    private volatile static Singleton INSTANCE;

    private Singleton() {
   
   }

    public static Singleton getInstance() {
   
   
        if (INSTANCE == null) {
   
   
            synchronized (Singleton.class) {
   
   
                if (INSTANCE == null) {
   
   
                    INSTANCE = new Singleton();
                }
            }
        }
        return INSTANCE;
    }
}

3. 静态内部类(Thread-safe Lazy Initialization)

利用类加载机制保证线程安全,延迟初始化。

public class Singleton {
   
   
    private Singleton() {
   
   }

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

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

4. 枚举单例

最简洁、安全的实现方式,天然线程安全,防止反射攻击。

public enum Singleton {
   
   
    INSTANCE;
}

5. 常见问题与解决

5.1 反射攻击

通过反射创建新的实例,绕过单例约束。枚举单例可以防止这种情况。

Singleton singleton = Singleton.class.getDeclaredConstructor().newInstance();

5.2 序列化与反序列化

单例对象被序列化和反序列化时,可能会创建多个实例。在单例类上实现readResolve()方法来返回已存在的实例。

private Object readResolve() {
   
   
    return INSTANCE;
}

5.3 单例的生命周期

单例的生命周期与应用相同,如果需要在特定条件下销毁,需要额外处理。

6. 易错点与避免方法

6.1 避免在静态初始化器中创建实例

静态初始化器在类加载时执行,可能导致不必要的实例化。

6.2 注意线程安全

在多线程环境中,确保单例的创建是线程安全的。

6.3 考虑可测试性

设计单例时,考虑测试需求,如提供构造函数的友元访问。

7. 结语

单例模式在许多场景下都非常有用,但使用时需谨慎,避免滥用。理解各种实现方式及其优缺点,根据项目需求选择合适的方法。同时,注意单例的生命周期、线程安全和测试性,以确保代码的质量和可维护性。


掌握单例模式的实现方式,有助于你在实际项目中更好地组织代码和管理资源。不断学习和实践,将使你的设计更加优雅和高效。

目录
相关文章
|
14天前
|
设计模式 SQL 安全
【设计模式】第二篇:单例模式的几种实现And反射对其的破坏
一个普通实例化,一个反射实例化 但是我们如果通过反射的方式进行实例化类,会有什么问题呢? public static void main(String[] args) throws Exception { Lazy1 lazy1 = getLazy1();
20 5
|
30天前
|
设计模式 Java API
【设计模式】JAVA Design Patterns——Combinator(功能模式)
【设计模式】JAVA Design Patterns——Combinator(功能模式)
|
26天前
|
设计模式 Java 数据库连接
【重温设计模式】代理模式及其Java示例
【重温设计模式】代理模式及其Java示例
|
1月前
|
设计模式 监控 Java
【设计模式】JAVA Design Patterns——Circuit Breaker(断路器模式)
【设计模式】JAVA Design Patterns——Circuit Breaker(断路器模式)
|
1天前
|
设计模式 开发框架 Java
java设计模式面试题大全含答案
java设计模式面试题大全含答案
|
1天前
|
安全 Java 编译器
Kotlin和Java 单例模式
Kotlin和Java 单例模式
8 1
|
3天前
|
设计模式 监控 安全
屏幕监控软件的设计模式:深入理解Java EE
在Java EE环境中,屏幕监控软件采用生产者-消费者设计模式,`ScreenCaptureProducer`类捕获屏幕数据并放入队列,`ScreenCaptureConsumer`负责处理和提交。数据每5分钟通过定时任务和RESTful API自动提交至网站,提升管理效率。该方案支持实时监控、数据分析和高效的数据处理。
21 2
|
28天前
|
设计模式 Java 数据库
【设计模式】JAVA Design Patterns——Converter(转换器模式)
转换器模式旨在实现不同类型间的双向转换,减少样板代码。它通过通用的Converter类和特定的转换器(如UserConverter)简化实例映射。Converter类包含两个Function对象,用于不同类型的转换,同时提供列表转换方法。当需要在逻辑上对应的类型间转换,或处理DTO、DO时,此模式尤为适用。
【设计模式】JAVA Design Patterns——Converter(转换器模式)
|
8天前
|
设计模式 存储 安全
Java中的23种设计模式
Java中的23种设计模式
9 1
|
2天前
|
设计模式 Java Spring
java设计模式总结
java设计模式总结