Java设计模式:创建型模式→单例模式

Java 单例模式详解

1. 定义

单例模式(Singleton Pattern)是一种创建型设计模式,其核心思想是确保某个类在整个应用程序中只有一个实例,并提供全局访问点。在很多情况下,例如访问共享资源或管理全局状态,单例模式非常有用。

2. 基本思想

单例模式的基本思想是通过控制实例化过程来限制一个类的实例数目。通过私有化构造函数和提供公共的静态方法来获取实例,以确保在应用程序的整个生命周期中,只有一个实例存在。

3. 基本原理

单例模式的核心原理是,利用类的私有构造函数,防止外部通过 new 关键字创建其对象。同时,通过静态方法或静态变量来访问唯一的实例。这种方式能有效避免多次实例化和资源浪费。
Java设计模式:创建型模式→单例模式_第1张图片

更多实用资源:

http://sj.ysok.net/jydoraemon 访问码:JYAM

4. 实现方式

4.1 饿汉式

这种方式在类加载时就创建好实例,因此在多线程环境下是线程安全的。

public class Singleton {
    // 静态实例在类加载时被创建
    private static final Singleton instance = new Singleton();

    // 私有构造函数
    private Singleton() { }

    // 提供公共的静态方法获取实例
    public static Singleton getInstance() {
        return instance;
    }
}
代码分析
  • 私有构造函数:防止其他类通过构造方法创建实例。
  • 静态实例:类加载时创建,确保了类的唯一性。
  • 静态方法:提供全局访问点。

4.2 懒汉式

此种方式在需要时创建实例,虽然实现简单,但在多线程情况下需要加锁,可能影响性能。

public class Singleton {
    private static Singleton instance;

    // 私有构造函数
    private Singleton() { }

    // 提供公共的静态方法获取实例
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
代码分析
  • 同步方法:保证在多线程环境下的安全。
  • 懒加载:仅在需要时创建实例。

4.3 双重检查锁

为了解决懒汉式的性能问题,同时保持线程安全性,可以使用双重检查锁。

public class Singleton {
    private static volatile Singleton instance;

    // 私有构造函数
    private Singleton() { }

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
代码分析
  • volatile:确保在多线程环境下实例的可见性。
  • 双重检查:第一次检查避免加锁提高效率。

4.4 静态内部类

使用静态内部类来实现单例,结合懒加载和线程安全的优点。

public class Singleton {
    // 私有构造方法
    private Singleton() { }

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

    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }
}
代码分析
  • 静态内部类:只有在 getInstance 方法被调用时才会加载,提高了性能。
  • 线程安全:JVM保证静态类的线程安全。

4.5 枚举实现

利用枚举类型的特性来实现单例模式,简洁且线程安全。

public enum Singleton {
    INSTANCE;

    // 可定义其他方法
    public void someMethod() { }
}
代码分析
  • 枚举类:枚举的实例在类加载时自动创建,防止多重实例化。

5. 工作流程

  1. 创建类:定义一个类,其中包含私有构造函数和返回对象的静态方法。
  2. 控制创建实例:通过私有构造函数限制实例化,只能通过静态方法访问。
  3. 存储唯一实例:通过静态变量存储唯一实例,并在应用中全局访问。

6. 变种

  1. 多重单例:有时候,我们可能希望某个类能够有多个单例,例如根据某个条件返回不同的实例。
  2. 懒汉式单例及其变种:懒汉式可以分为多种,不同的加锁方式。
  3. 线程封闭的单例:每个线程都有一个独立的单例实例。

7. 实际应用

  • 配置管理器:集中管理应用的配置信息。
  • 日志管理:日志功能需要全局唯一的访问点。
  • 线程池:对线程的管理需要统一的接口和实例。

8. 使用场景

  • 当需要控制资源的数量时,例如数据库连接池。
  • 需要全局共享数据或状态时。
  • 需要避免重复实例化时。

9. 优缺点

优点

  • 全局访问:能在全局范围共享实例。
  • 控制实例数量:避免多个实例带来的冲突或资源浪费。
  • 延迟加载:某些实现方式可实现懒加载,提高性能。

缺点

  • 不容易扩展:如果需要多个实例就无法使用单例模式。
  • 隐藏类的依赖:单例可能导致代码中难以跟踪类的依赖关系。
  • 潜在的多线程问题:若实现不当,可能带来线程安全问题。

10. 最佳实践

  • 尽量使用枚举实现单例。
  • 对于较复杂的业务逻辑,可以考虑使用IoC容器进行管理。
  • 在多线程环境下,优先考虑线程安全的实现方式。

11. 注意事项

  • 确保构造方法是私有的。
  • 考虑单例类是否需要延迟初始化,选择合适的实现方式。
  • 避免序列化和反序列化广播多个实例的问题。

12. 常见误区

  • 单例模式可以随意使用:单例并不是解决所有问题的方案。
  • 单例可以被继承:单例通常应该是 final,不允许被继承。
  • 所有类都能使用单例模式:并不是所有情况下都适合使用单例,需根据业务需求判断。

13. 常见问题

  • 单例类是否可以使用继承?

    • 单例类通常不应该被继承,因为这可能会导致产生多个实例。
  • 如何实现线程安全的单例?

    • 应用双重检查锁定或使用静态内部类。
  • 如果单例类需要序列化怎么办?

    • 需要添加 readResolve 方法来防止反序列化创建新的实例。

14. 总结

单例模式是一种广泛使用的设计模式,通过控制实例化过程确保类只有一个实例,并提供全局访问点。Java 中有多种实现方式,各具优缺点。在使用单例模式时,开发者需要根据具体情况选择合适的实现,确保线程安全并避免常见误区。合理运用单例模式能够有效提升程序的设计质量和性能。

你可能感兴趣的:(Java,设计模式,单例模式,java,设计模式)