单例计划模式

打印 上一主题 下一主题

主题 1039|帖子 1039|积分 3117

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
在软件开发的广阔范畴中,我们常常会碰到这样的场景:某些类在整个应用程序中只需要一个实例存在。比方,数据库连接池需要确保整个体系中只有一个连接池实例,以制止资源的浪费和管理的混乱;日志记载器也通常只需要一个实例,确保日志记载的一致性和准确性。单例模式就是为解决这类问题而生的,它是一种创建型计划模式,保证一个类仅有一个实例,并提供一个全局访问点。

一、单例模式的定义与特点

1.1 定义

单例模式确保一个类只有一个实例,并提供一个全局访问点来访问这个唯一实例。这意味着无论在应用程序的哪个部门请求该类的实例,得到的都是同一个对象。
1.2 特点



  • 唯一性:在整个应用程序生命周期内,该类只有一个实例存在。
  • 全局访问:提供一个全局的静态方法或属性,用于获取这个唯一实例,方便在程序的任何地方进行访问。

二、单例模式的实现方式

2.1 饿汉式单例

饿汉式单例在类加载时就立即创建实例,代码如下:
  1. public class EagerSingleton {
  2.     // 类加载时就创建实例
  3.     private static final EagerSingleton instance = new EagerSingleton();
  4.     // 私有构造函数,防止外部实例化
  5.     private EagerSingleton() {}
  6.     // 提供全局访问点
  7.     public static EagerSingleton getInstance() {
  8.         return instance;
  9.     }
  10. }
复制代码
饿汉式单例的优点是实现简单,在类加载时就创建实例,保证了实例在多线程情况下的唯一性。缺点是如果该单例对象在整个应用程序中使用频率不高,会造成资源浪费,由于在类加载时就创建了实例,而不管是否真的需要。
2.2 懒汉式单例(线程不安全)

懒汉式单例在第一次使用时才创建实例,代码如下:
  1. public class LazySingleton {
  2.     private static LazySingleton instance;
  3.     private LazySingleton() {}
  4.     // 第一次调用时创建实例
  5.     public static LazySingleton getInstance() {
  6.         if (instance == null) {
  7.             instance = new LazySingleton();
  8.         }
  9.         return instance;
  10.     }
  11. }
复制代码
懒汉式单例的优点是耽误实例化,只有在真正需要时才创建实例,节省了资源。但缺点是在多线程情况下,可能会创建多个实例,不具备线程安全性。比方,当两个线程同时判断 instance 为 null 时,它们都会创建一个新的实例,导致违反单例模式的唯一性原则。
2.3 懒汉式单例(线程安全 - 同步方法)

为相识决懒汉式单例的线程安全问题,可以在 getInstance 方法上添加 synchronized 关键字,使其成为线程安全的,代码如下:
  1. public class LazySingletonSyncMethod {
  2.     private static LazySingletonSyncMethod instance;
  3.     private LazySingletonSyncMethod() {}
  4.     // 线程安全的获取实例方法
  5.     public static synchronized LazySingletonSyncMethod getInstance() {
  6.         if (instance == null) {
  7.             instance = new LazySingletonSyncMethod();
  8.         }
  9.         return instance;
  10.     }
  11. }
复制代码
这种方式固然保证了线程安全,但由于 synchronized 关键字修饰了整个方法,在多线程情况下,每次调用 getInstance 方法都会进行同步操作,性能较低。特别是在高并发场景下,可能会成为性能瓶颈。
2.4 懒汉式单例(线程安全 - 双重查抄锁)

双重查抄锁机制结合了懒加载和线程安全,同时进步了性能,代码如下:
  
  1. public class LazySingletonDoubleCheck {
  2.     private static volatile LazySingletonDoubleCheck instance;
  3.     private LazySingletonDoubleCheck() {}
  4.     public static LazySingletonDoubleCheck getInstance() {
  5.         if (instance == null) {
  6.             synchronized (LazySingletonDoubleCheck.class) {
  7.                 if (instance == null) {
  8.                     instance = new LazySingletonDoubleCheck();
  9.                 }
  10.             }
  11.         }
  12.         return instance;
  13.     }
  14. }
复制代码
这里使用了 volatile 关键字修饰 instance,确保了 instance 的可见性和禁止指令重排序。外层的 if (instance == null) 查抄是为了制止不须要的同步开销,只有当 instance 为 null 时才进入同步块。内层的 if (instance == null) 查抄是为了在多线程情况下确保只有一个实例被创建。
2.5 静态内部类实现单例

通过静态内部类实现单例,既保证了懒加载,又保证了线程安全,代码如下:
  
  1. public class StaticInnerClassSingleton {
  2.     private StaticInnerClassSingleton() {}
  3.     // 静态内部类
  4.     private static class SingletonHolder {
  5.         private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();
  6.     }
  7.     // 提供全局访问点
  8.     public static StaticInnerClassSingleton getInstance() {
  9.         return SingletonHolder.INSTANCE;
  10.     }
  11. }
复制代码
这种方式利用了类加载机制的特性,只有在调用 getInstance 方法时,静态内部类 SingletonHolder 才会被加载,从而创建实例。由于类加载过程是线程安全的,以是这种方式既实现了懒加载,又保证了线程安全。
2.6 枚举实现单例

在 Java 中,枚举范例本身就保证了实例的唯一性,以是可以用枚举来实现单例,代码如下:
  
  1. public enum EnumSingleton {
  2.     INSTANCE;
  3.     // 可以在这里添加其他方法和属性
  4.     public void doSomething() {
  5.         System.out.println("执行单例方法");
  6.     }
  7. }
复制代码
使用枚举实现单例非常简便,并且天然支持序列化和反序列化,不会出现多个实例的问题。它是实现单例模式的一种推荐方式,尤其是在需要考虑序列化和反序列化场景下。

三、单例模式的应用场景

3.1 资源管理



  • 数据库连接池:在应用程序中,数据库连接是一种宝贵的资源。使用单例模式创建数据库连接池,可以确保整个应用程序共享一个连接池,制止频繁创建和烧毁数据库连接带来的性能开销。
  • 线程池:线程池同样需要保证唯一性,以合理管理和复用线程资源。通过单例模式,整个应用程序可以使用同一个线程池,进步线程的使用服从。
3.2 日志记载

日志记载器通常只需要一个实例,确保全部的日志记载都能按照统一的规则和格式进行处置惩罚。比方,在一个大型企业级应用中,各个模块的日志都通过同一个日志记载器实例进行记载,方便后续的日志分析和故障排查。
3.3 设置管理

应用程序的设置信息(如数据库设置、体系参数等)在整个应用程序中通常是共享的。使用单例模式创建一个设置管理器,负责读取和管理设置信息,可以保证设置的一致性和全局访问性。

四、单例模式的优缺点

4.1 优点



  • 资源共享:确保在整个应用程序中只有一个实例,方便资源的共享和管理,制止资源的重复创建和浪费。
  • 全局访问:提供了一个全局访问点,方便在应用程序的任何地方获取该实例,便于代码的编写和维护。
  • 进步性能:在某些场景下,如数据库连接池,使用单例模式可以减少资源的创建和烧毁次数,从而进步体系的性能。
4.2 缺点



  • 测试困难:由于单例模式的实例是全局唯一的,在单位测试中可能会导致测试结果的不可重复性。比方,在一个测试方法中修改了单例对象的状态,可能会影响到其他测试方法的执行结果。
  • 不易扩展:如果在后期需要对单例类进行扩展,可能会比较困难,由于单例模式的结构相对固定,修改可能会影响到整个应用程序中对该单例的使用。
  • 可能导致内存泄漏:如果单例对象持有对其他资源(如文件句柄、网络连接等)的引用,并且在应用程序竣事时没有准确释放这些资源,可能会导致内存泄漏。

五、结语

希望这篇文章可以或许帮助您更好地理解单例计划模式,并为您的编程实践提供指导。若实践有看法或疑问,欢迎评论区交流。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

饭宝

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表