欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 旅游 > 单例模式介绍

单例模式介绍

2025/4/28 17:04:36 来源:https://blog.csdn.net/weixin_54925172/article/details/147530384  浏览:    关键词:单例模式介绍

   单例模式大家都很清楚,最常见的是饿汉式与懒汉式。也有不常见的静态内部类式与枚举式以及,懒汉式的线程安全版本。

   单例模式常被用于全局式的配置管理(数据库连接池,日志管理器),资源共享(线程池,缓存控制器),状态管理(程序计数器)等。

一. 单例模式的实现方式

1,饿汉式单例模式

      特点:线程安全,但在类加载时就创建实例,不管是否使用都会占用资源

/*** 饿汉式单例模式* 特点:线程安全,但在类加载时就创建实例,不管是否使用都会占用资源*/
public class SingletonEager {// 在类加载时就创建实例private static final SingletonEager instance = new SingletonEager();// 私有构造函数,防止外部实例化private SingletonEager() {}// 提供全局访问点public static SingletonEager getInstance() {return instance;}
}

 2, 懒汉式单例模式(线程不安全版本)

        特点:延迟加载,但在多线程环境下可能创建多个实例

/*** 懒汉式单例模式(线程不安全版本)* 特点:延迟加载,但在多线程环境下可能创建多个实例*/
public class SingletonLazy {// 声明实例,但不创建private static SingletonLazy instance;// 私有构造函数private SingletonLazy() {}// 提供全局访问点,在首次调用时创建实例public static SingletonLazy getInstance() {if (instance == null) {instance = new SingletonLazy();}return instance;}
}

3,线程安全的懒汉式单例模式 

      特点:延迟加载且线程安全,但同步方法影响性能

public class SingletonLazySafe {private static SingletonLazySafe instance;private SingletonLazySafe() {}// 使用synchronized关键字确保线程安全public static synchronized SingletonLazySafe getInstance() {if (instance == null) {instance = new SingletonLazySafe();}return instance;}
}

4,双重检查锁定的单例模式

      特点:延迟加载,线程安全,且大部分情况下避免了同步锁的性能影响

/*** 双重检查锁定的单例模式* 特点:延迟加载,线程安全,且大部分情况下避免了同步锁的性能影响*/
public class SingletonDoubleCheck {// volatile关键字确保多线程环境下的可见性private static volatile SingletonDoubleCheck instance;private SingletonDoubleCheck() {}public static SingletonDoubleCheck getInstance() {// 第一次检查if (instance == null) {// 同步锁synchronized (SingletonDoubleCheck.class) {// 第二次检查if (instance == null) {instance = new SingletonDoubleCheck();}}}return instance;}
}

5,静态内部类单例模式 

      特点:延迟加载,线程安全,且不需要同步 

/*** 静态内部类单例模式* 特点:延迟加载,线程安全,且不需要同步*/
public class SingletonStaticInner {private SingletonStaticInner() {}// 静态内部类,只有在首次调用getInstance()时才会被加载private static class SingletonHolder {private static final SingletonStaticInner INSTANCE = new SingletonStaticInner();}public static SingletonStaticInner getInstance() {return SingletonHolder.INSTANCE;}
}

6, 枚举单例模式

       特点:最简洁的实现,自动支持序列化,绝对防止多次实例化

/*** 枚举单例模式* 特点:最简洁的实现,自动支持序列化,绝对防止多次实例化*/
public enum SingletonEnum {INSTANCE;// 业务方法示例public int findLongestPalindrome(String s) {if (s == null || s.length() < 1) return 0;int maxLength = 0;for (int i = 0; i < s.length(); i++) {// 处理奇数长度的回文串int len1 = expandAroundCenter(s, i, i);// 处理偶数长度的回文串int len2 = expandAroundCenter(s, i, i + 1);maxLength = Math.max(maxLength, Math.max(len1, len2));}return maxLength;}private int expandAroundCenter(String s, int left, int right) {while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {left--;right++;}return right - left - 1;}
}

        

二. 那么单例模式与单例bean的区别在哪呢?为什么选用单例模式,不用单例bean?

我们先来回顾一下单例bean,一般来说bean是指的是Spring容器的管理对象。由IOC创建并管理,其生命周期伴随着Spring容器。

而单例模式,本身是一种设计模式,一种编程的概念。

先看看具体有哪些不同。

1,实现方式

单例模式:需要开发者手动创建和管理

单例bean:由Spring框架自动管理

2,作用域

单例模式:项目整体

单例bean:Spring IOC容器

3,线程安全

单例模式:需要开发者手动实现

单例bean:默认线程不安全,如有成员变量,需开发者手动使用同步锁维护线程安全

4,生命周期

单例模式:类加载器控制,通常伴随程序的整个生命周期

单例bean:由容器管理

5,应用场景区别

单例模式:全局配置管理(如数据库连接池),工具类(如日志管理器),硬件访问控制(如打印机服务)。

单例bean:需要Spring管理的各种层级对象,缓存与事务管理器等配置

三. 单例模式的类一定只会有一个对象实例么?

我们首先参考作用域,单例模式一般是伴随整个程序。这是基于单个jvm的情况。在分布式环境下相当于每个jvm都有一个相同的单例对象,也就是全局范围内多个对象。

而在单个jvm中也是有可能出现单例被破坏的情况的。最简单的就是利用反射。

1,反射攻击

即使单例类的构造函数被声明为 private,通过反射仍可获取构造方法并设置其可访问性为 true,从而强制创建新实例。

Class<?> clazz = Singleton.class;
Constructor<?> constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);  // 绕过访问控制
Singleton newInstance = (Singleton) constructor.newInstance();

2,序列化与反序列化

如果单例类实现了 Serializable 接口,反序列化时会创建新的实例。

3,有多个类加载器加载同一单例对象

不同类加载器加载同一个类会生成多个实例。

4,多线程未同步的懒汉式

在多线程高并发环境下,可能会创建出多个实例。

5,分布式系统或集群环境

在分布式系统中,每个 JVM 进程会维护自己的单例实例,导致全局范围内存在多个实例。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词