单例模式的多种写法

目录

正文:

1.概念

2.饿汉式

3.懒汉式

3.1线程不安全的懒汉式

3.2线程安全的懒汉式

4.双重检查式

总结:


正文:

1.概念

单例模式(Singleton Pattern)是软件设计中常见的设计模式之一。它确保一个类只有一个实例,并提供一个全局访问点。这种模式在全局状态下的数据管理和控制、资源优化等方面非常有用。在Java中实现单例模式有多种方式,每种方式都有其特点和适用场景。

2.饿汉式

其特点是在类加载时就立即初始化实例,并且只创建一个实例。实例在类加载时就已经创建,所以在任何线程访问getInstance()方法之前,实例已经存在,因此不存在线程同步问题。

java 复制代码
public class EagerSingleton {
    // 私有静态实例,类加载时就初始化
    private static final EagerSingleton instance = new EagerSingleton();

    // 私有构造函数,防止外部通过new创建实例
    private EagerSingleton() {}

    // 公有的静态方法,提供全局访问点
    public static EagerSingleton getInstance() {
        return instance;
    }
}

优点:

  1. 实现简单:代码简洁,易于理解和维护。
  2. 无需同步:由于实例在类加载时就已经创建,不需要考虑线程同步问题。

缺点:

  1. 资源占用:不管是否需要,实例都会被创建,可能导致不必要的资源占用。
  2. 不易扩展:如果需要改变单例的创建逻辑,或者需要按需加载,饿汉式可能不是最佳选择。

适用场景:

  • 单例对象的创建过程不需要消耗大量资源。
  • 单例对象需要频繁访问,且访问速度很重要。
  • 确定单例对象的生命周期与应用程序的生命周期相同。

3.懒汉式

其核心特点是类实例在第一次使用时才创建,这种方式被称为"懒"初始化。懒汉式单例模式可以进一步细分为线程不安全的懒汉式和线程安全的懒汉式。

3.1线程不安全的懒汉式

这种实现方式的特点是在实例化对象时不进行同步处理,因此可能存在线程安全问题。

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

    private LazySingleton() {}

    //没有加锁
    public static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

如果在单线程环境下运行,这种方式是简单且高效的。但在多线程环境下,如果两个线程如果同时检查instance是否为null,并且都发现它是null,那么它们都可能创建一个新的实例,这将导致instance变量引用多个实例,违反了单例模式的原则。

3.2线程安全的懒汉式

为了解决线程安全问题,可以在创建实例时进行同步处理。可以通过使用synchronized关键字来实现。

java 复制代码
public class ThreadSafeLazySingleton {
    //防止内存可见性和重排序问题
    private static volatile ThreadSafeLazySingleton instance;

    private ThreadSafeLazySingleton() {}
     
    //通过加锁来保证线程安全
    public static synchronized ThreadSafeLazySingleton getInstance() {
        if (instance == null) {
            instance = new ThreadSafeLazySingleton();
        }
        return instance;
    }
}

在这个版本中,getInstance()方法被声明为synchronized,这意味着同一时间只有一个线程能够进入这个方法。volatile关键字确保了instance变量的读写操作对所有线程都是可见的,防止了内存中的变量值因线程内部缓存而出现不一致的情况。

优点:

  1. 延迟加载:实例在第一次使用时才会被创建,避免了资源浪费。
  2. 节省内存:只有在需要时才会创建实例,避免了一开始就创建对象的内存消耗。
  3. 适用于资源敏感型应用:适用于那些需要在应用启动时尽量减少资源占用的场景。

缺点:

  1. 线程不安全:在多线程环境下,可能会出现多个线程同时进入创建实例的逻辑,导致创建多个实例的问题。

  2. 需要额外考虑线程安全性:为了解决线程安全问题,需要在getInstance()方法上添加同步锁,会影响性能。

  3. 可能引起性能问题:由于需要在方法上添加同步锁,可能会导致性能下降,特别是在高并发环境下。

适用场景:

  • 资源敏感型应用:对资源占用有较高要求的应用,可以使用懒汉式单例来延迟实例化。

  • 单线程环境:在单线程环境下,懒汉式单例可以简单实现且没有线程安全问题。

  • 非高并发场景:在并发度不高的场景下,懒汉式单例可以满足需求。

4.双重检查式

双重检查锁定是一种优化的线程安全懒汉式实现,它通过两次检查实例是否已创建来减少同步的开销。

java 复制代码
public class Singleton {
    // 声明,并用volatile修饰,保证在多线程环境下的有序性
    private volatile static Singleton instance = null;
    // 私有构造方法
    private Singleton () {}
    // 对外提供一个获取实例的方法,
    public static Singleton getInstance() {
        // 使用双重if检查, 降低锁竞争的频率
        if (instance == null) {
            // instance没有被实例化才去加锁
            synchronized (Singleton.class) {
                // 获取到锁后再检查一遍,确认instance没有被实例化后去真正的实例化
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

在这个实现中,第一次检查instance是否为null是不加锁的,只有在instance确实为null时,才会进入同步块进行第二次检查和实例化。这种实现既保证了线程安全,又提高了性能,因为它避免了每次调用getInstance()时都进行同步。

优点:

  1. 性能优化:双重检查锁定的主要优点是它减少了每次获取单例实例时的同步开销。只有当实例尚未创建时,才会进行同步和创建实例。一旦实例被创建,后续的调用都不需要同步,从而提高了性能。

  2. 线程安全:通过在实例化过程中使用同步块,双重检查锁定确保了即使在多线程环境中,也只有一个实例被创建。

  3. 非强制性同步:与始终使用synchronized方法或块相比,双重检查锁定只在必要时进行同步,这避免了不必要的性能损失。

缺点:

  1. 复杂性:双重检查锁定的实现相对复杂,需要在代码中进行两次检查,容易引入错误和难以维护。

  2. 性能开销:虽然双重检查锁定可以减少加锁的频率,但仍需要进行两次检查,可能会引入性能开销。

使用场景:

双重检查锁定适用于以下场景:

  • 性能敏感的应用:当你需要频繁获取单例实例,并且实例化过程相对昂贵时,双重检查锁定可以提供更好的性能。

  • 多线程环境:在多线程环境中,你需要确保线程安全,同时希望减少同步的开销。

总结:

单例模式是一种常用的设计模式,通过保证一个类只有一个实例,提供全局访问点,方便对实例进行管理。在Java中,可以通过不同的实现方式来创建单例对象,每种实现方式都有其优缺点。在应用中,需要根据实际情况选择合适的单例实现方式,并注意线程安全和内存管理问题。

相关推荐
niucloud-admin4 分钟前
java服务端——controller控制器
java·开发语言
To Be Clean Coder5 分钟前
【Spring源码】通过 Bean 工厂获取 Bean 的过程
java·后端·spring
Fortunate Chen11 分钟前
类与对象(下)
java·javascript·jvm
程序员水自流12 分钟前
【AI大模型第9集】Function Calling,让AI大模型连接外部世界
java·人工智能·llm
‿hhh15 分钟前
综合交通运行协调与应急指挥平台项目说明
java·ajax·npm·json·需求分析·个人开发·规格说明书
小徐Chao努力15 分钟前
【Langchain4j-Java AI开发】06-工具与函数调用
java·人工智能·python
无心水18 分钟前
【神经风格迁移:全链路压测】33、全链路监控与性能优化最佳实践:Java+Python+AI系统稳定性保障的终极武器
java·python·性能优化
萧曵 丶27 分钟前
Synchronized 详解及 JDK 版本优化
java·多线程·synchronized
夏幻灵41 分钟前
JAVA基础:基本数据类型和引用数据类型
java·开发语言
weixin199701080161 小时前
闲鱼 item_get - 商品详情接口对接全攻略:从入门到精通
java·后端·spring