自学内容网 自学内容网

单例设计模式

简介

单例模式(Singleton Pattern)指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点,属于创建型设计模式。

单例的核心实现逻辑

单例模式(Singleton)的目的是为了保证在一个进程中,某个类有且仅有一个实例。

因为这个类只有一个实例,因此,自然不能让调用方使用new Xyz()来创建实例了。所以,单例的构造方法必须是private,这样就防止了调用方自己创建实例,但是在类的内部,是可以用一个静态字段来引用唯一创建的实例的。总结起来就三步:

  1. 只有private构造方法,确保外部无法实例化;
  2. 通过private static变量持有唯一实例,保证全局唯一性;
  3. 通过public static方法返回此唯一实例,使外部调用方能获取到实例。

饿汉单例模板

  1. 代码

    // 饿汉单例
    public class SingletonEager {
        // 1. 构造方法私有化
        private SingletonEager() {
        }
    
        // 2. 静态字段引用唯一实例
        public static SingletonEager INSTANCE = new SingletonEager();
    
        // 3. 通过静态方法返回实例
        public static SingletonEager getInstance() {
            return INSTANCE;
        }
    }
    
  2. 优点

  • 线程安全:由于实例化发生在类加载的时候,而 Java 类加载机制保证了线程安全性,所以不需要加锁机制来保证多个线程访问的安全性。
  • 简单:实现起来非常简单,没有复杂的逻辑。
  • 没有同步开销:由于实例在类加载时已经创建,因此在获取实例时无需进行同步操作。
  1. 缺点
  • 内存利用率:不论是否需要使用该实例,只要应用程序运行就会占用内存,可能会造成资源浪费。
  • 延迟初始化:如果系统中存在大量的单例类,并且这些类在系统运行初期不会马上用到,那么在系统启动阶段就会消耗较多的内存资源。
  1. 使用场景
  • 当你确定这个单例对象在整个应用生命周期中都会频繁使用,并且创建对象的成本不是很高时。
  • 在多线程环境中,如果单例对象的创建成本较低,并且需要保证线程安全的情况下使用。

懒汉单例模板

  1. 代码

    
    // 懒汉单例
    public class SingletonSimpleLazy {
        // 1. 构造方法私有化
        private SingletonSimpleLazy() {
        }
        // 2.单例对象,初始为null
        private static SingletonSimpleLazy instance = null;
        // 3. 第一次调用getInstance()时才初始化全局唯一实例
        public static SingletonSimpleLazy getInstance() {
            if (instance == null) {
                instance = new SingletonSimpleLazy();
            }
            return instance;
        }
    }
    
  2. 优点

  • 延迟加载:只有当第一次调用 getInstance() 方法时才会创建单例对象,从而节省了系统启动时的资源开销。
  • 节省内存:如果单例对象很大或者创建成本较高,那么只有在需要时才创建,可以有效减少内存消耗。
  1. 缺点
  • 线程安全问题:如果没有正确处理并发访问的问题,在多线程环境下可能会导致创建多个实例。
  • 性能影响:每次调用 getInstance() 都需要检查是否已经创建了实例,这可能会引入额外的性能开销。
  • 同步开销:为了保证线程安全,通常会采用同步机制(如 synchronized 关键字),但这会影响性能。
  1. 使用场景
  • 如果单例对象创建成本较高,并且在整个应用生命周期内并不总是会被用到。
  • 当需要确保单例模式的线程安全性,并且不介意为此付出一定的性能代价。

双重检查锁定单例模板

  1. 代码

// 双重检查单例
public class SingletonDoubleCheckLazy {
    // 1. 构造方法私有化
    private SingletonDoubleCheckLazy() {
    }

    // 2. 单例对象,初始为null
    private volatile static SingletonDoubleCheckLazy instance = null;

    // 3. 提供全局访问点
    public static SingletonDoubleCheckLazy getInstance() {
        if (instance == null) { // 第一次检查
            synchronized (SingletonDoubleCheckLazy.class) {
                if (instance == null) { // 第二次检查
                    instance = new SingletonDoubleCheckLazy();
                }
            }
        }
        return instance;
    }
}
  1. 优点
  • 延迟加载:只有在首次请求时创建实例,节省了系统启动时的资源。
  • 线程安全:通过同步内部创建逻辑,保证了多线程环境下的安全性。
  • 高效:只在必要时进行同步,避免了每次获取实例时都需要同步所带来的性能损失。
  1. 缺点
  • 复杂性:实现相对复杂,需要理解 Java 内存模型和 volatile 关键字的作用。
  • 编译器优化问题:早期 JVM 存在指令重排序的问题,可能导致对象创建未完成就返回给调用者。现代 JVM 已经解决了这个问题,但仍需注意 volatile 的正确使用。
  • 反序列化问题:如果对象可以被序列化,那么反序列化可能会创建新的实例,破坏单例性质。
  1. 使用场景
  • 当单例对象创建成本较高,并且需要在多线程环境中保持线程安全。
  • 当单例对象的创建时机不确定,且创建后需要频繁访问时。
  • 在分布式环境中,如果需要全局唯一的单例对象。

枚举单例模板(推荐)


// 枚举单例
public enum SingletonEnum {
    INSTANCE;
    private Object data;

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public static SingletonEnum getInstance(){
        return INSTANCE;
    }
}
  1. 优点
  • 线程安全:枚举类型的单例天生就是线程安全的,不需要额外的同步机制。
  • 序列化安全:枚举类型可以自动处理序列化问题,防止反序列化产生新的实例。
  • 简洁:实现非常简单,不需要额外的代码来维护单例性。
  • 易于理解和维护:枚举类型的单例模式易于理解和维护,因为其逻辑非常直观。
  1. 缺点
  • 功能单一:如果单例类需要提供更多的功能,如配置加载、懒加载等,枚举单例可能不是最佳选择。
  • 扩展性有限:枚举类型主要用于定义常量,如果需要扩展单例的功能,可能需要在枚举类型之外添加更多的类或接口。
  1. 使用场景
  • 当你需要一个绝对安全的单例对象,并且不需要额外的懒加载或延迟初始化时。
  • 当单例对象不需要复杂的初始化过程,只需简单地提供一些静态方法或属性。
  • 在多线程环境中,需要确保单例对象的线程安全性和序列化安全性。

总结

单例模式在现实生活中的应用非常广泛,例如公司CEO、部门经理等都属于单例模型。J2EE标准中的ServletContext和ServletContextConfig、Spring框架应用中的ApplicationContext、数据库中的连接池等也都是单例模式。对于Java来说,单例模式可以保证在一个JVM中只存在单一实例。单例模式的应用场景主要有以下几个方面。
(1)需要频繁创建的一些类,使用单例可以降低系统的内存压力,减少GC。
(2)某些类创建实例时占用资源较多,或实例化耗时较长,且经常使用。
(3)频繁访问数据库或文件的对象。
(4)对于一些控制硬件级别的操作,或者从系统上来讲应当是单一控制逻辑的操作,如果有多个实例,则系统会完全乱套。


原文地址:https://blog.csdn.net/Android_xue/article/details/142559571

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!