前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >探索单例模式的奥秘

探索单例模式的奥秘

原创
作者头像
码匠er
发布2024-02-28 22:45:45
1260
发布2024-02-28 22:45:45
举报
文章被收录于专栏:设计模式设计模式

单例模式用于创建那些在软件系统中独一无二的对象。

在实际的开发过程中,为了节约系统的资源,有时需要确保系统中某个类的实例必须是唯一的,比如:线程池、缓存、网络请求等所有的操作都需要基于唯一的实例,我们就可以使用单例模式

1. 定义

单例模式确保了一个类只有一个实例,而且自行实例化并且向整个系统提供这个实例,这个类被称为单例类。它提供全局访问的方法。

2. 角色

  • Singleton单例类的内部实现只生成一个示例,同时提供一个静态的方法,向系统提供全局访问的方法。为了防止在外部对单例类实例化,将构造方法设置为private

3. 示例

单例的实现共有以下几种方式:

3.1 饿汉式

饿汉式的单例实现比较简单,其在类加载的时候,静态实例instance 就已创建并初始化好了。

代码语言:javascript
复制
 public class HungrySingleton {
     private static final HungrySingleton instance = new HungrySingleton();
     
     private HungrySingleton() {}
     
     public static HungrySingleton getInstance() {
         return instance;
     }
 }
  • 优点:线程安全
  • 缺点:不支持延迟加载(延迟加载可以节省内存)

3.2 懒汉式

懒汉式将对象的初始化延迟到获取实例的时候,为了保证线程安全添加了锁。

代码语言:javascript
复制
 public class LazySingleton {
     private static LazySingleton instance;
 ​
     private LazySingleton() {}
 ​
     public static synchronized LazySingleton getInstance() {
         if (instance == null) {
             instance = new LazySingleton();
         }
         return instance;
     }
 }
  • 优点:支持延时加载。
  • 缺点:获取对象的操作被加上了锁实现线程同步,影响了并发度。

3.3 双重检查

双重检查将懒汉式中的方法锁改为块锁,再次调用时不会进入synchronized代码块中。

代码语言:javascript
复制
 public class DoubleSingleton {
     // 1.4及更早版本如果不加volatile关键字会导致指令重排,高版本进行了优化,所以也可以不添加
     private static volatile DoubleSingleton instance;
 ​
     private DoubleSingleton() {}
 ​
     public static DoubleSingleton getInstance() {
         if (instance == null) {
             synchronized (DoubleSingleton.class) {
                 if (instance == null) {
                     instance = new DoubleSingleton();
                 }
             }
         }
         return instance;
     }
 }
  • 优点:支持延迟加载,线程安全,资源利用率高,第一次执行 getInstance 时才会被实例化,效率高。
  • 缺点:一次加载反应稍慢。

3.4 静态内部类

使用Java静态内部类的特性:Java 加载外部类的时候,不会创建内部类的实例,只有在外部类使用到内部类的时候才会创建内部类实例。

代码语言:javascript
复制
 public class InnerClassSingleton {
 ​
     private InnerClassSingleton() {}
 ​
     private static class Singleton{
         private static final Singleton instance = new Singleton();
     }
 ​
     public static Singleton getInstance() {
         return Singleton.instance;
     }
 }
  • 优点:线程安全、延迟加载、不需要获取锁。

3.5 枚举

用枚举来实现单例,是最简单的方式。这种实现方式通过 Java 枚举类型本身的特性,保证了实例创建的线程安全性和实例的唯一性。

代码语言:javascript
复制
 public enum EnumSingleton {
     INSTANCE; // 该对象全局唯一
 }

3.6 注册式单例

注册式单例是通过一个注册表(容器)来存储单例实例,根据键值进行管理。

代码语言:javascript
复制
 public class RegistrySingleton {
     private static Map<String, RegistrySingleton> map = new HashMap<>();
 ​
     static {
         RegistrySingleton registrySingleton = new RegistrySingleton();
         map.put(registrySingleton.getClass().getName(), registrySingleton);
     }
 ​
     private RegistrySingleton() {
     }
 ​
     public static RegistrySingleton getInstance(String className) {
         if (!map.containsKey(className)) {
             try {
                 map.put(className, (RegistrySingleton) Class.forName(className).newInstance());
             } catch (InstantiationException e) {
                 e.printStackTrace();
             } catch (IllegalAccessException e) {
                 e.printStackTrace();
             } catch (ClassNotFoundException e) {
                 e.printStackTrace();
             }
         }
         return map.get(className);
     }
 }
  • 优点:延迟加载、注册表可以提供全局访问点,方便管理系统中所有的单例;
  • 缺点:线程不安全、引入了注册表,增加复杂性。

3.7 CAS

CAS使用乐观锁的机制,通过自旋不断尝试更新值,实现了线程安全。

代码语言:javascript
复制
 public class CasSingleton {
     private static final AtomicReference<CasSingleton> INSTANCE = new AtomicReference<>();
 ​
     private CasSingleton() {
     }
     
     public static CasSingleton getInstance() {
         while (true) {
             CasSingleton singleton = INSTANCE.get();
             if (singleton != null) {
                 return singleton;
             }
             singleton = new CasSingleton();
             if (INSTANCE.compareAndSet(null, singleton)) {
                 return singleton;
             }
         }
     }
 }
  • 优点:线程安全、性能好、无死锁的风险,使用与高并发场景
  • 缺点:会出现ABA问题,不能保证公平性,硬件和平台依赖性较高

4. 应用场景

例模式适用于需要全局唯一实例、提供全局访问点以及确保一致性的场景。

  • 数据库连接池: 在数据库连接池中,为了节省资源和提高性能,通常需要保证只有一个连接池实例,以便管理和复用数据库连接。
  • 日志系统: 在应用程序中使用单例模式来管理日志输出,确保日志信息的一致性和集中管理。
  • 配置管理: 在配置管理中,单例模式可以用于加载和管理系统配置信息,以确保在整个系统中只有一个配置管理实例。
  • 线程池: 在多线程环境中,使用单例模式管理线程池,确保线程的创建和销毁能够集中控制,以便更好地管理系统资源。
  • 资源管理器: 在图形用户界面(GUI)应用程序中,单例模式可以用于实现资源管理器,确保只有一个资源管理器实例用于管理系统资源。
  • 缓存管理: 在需要缓存数据的场景中,单例模式可以用于管理缓存,确保缓存的一致性和集中管理。
  • GUI组件: 在图形用户界面中,一些全局的 GUI 组件,如窗口管理器、对话框管理器等,可以使用单例模式确保全局唯一性。
  • 计数器: 在一些需要生成唯一序列号或计数的情况下,可以使用单例模式来管理计数器,确保唯一性和一致性。
  • 系统状态管理: 在某些系统中,可能需要维护和管理系统的状态信息,例如登录状态、权限信息等,单例模式可以确保状态信息的一致性和全局访问。

我会持续更新关于技术的文章❤️🤎💚🧡💛 欢迎大家点赞👍 收藏 ⭐ 关注 💡三连支持一下~~~ 查看文章过程中有问题或者有需要修改的地方,欢迎私聊我哦 🗨🗨🗨 不管世界变成什么样,我们都要加强自己自身能力~✊✊✊

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 定义
  • 2. 角色
  • 3. 示例
    • 3.1 饿汉式
      • 3.2 懒汉式
        • 3.3 双重检查
          • 3.4 静态内部类
            • 3.5 枚举
              • 3.6 注册式单例
                • 3.7 CAS
                • 4. 应用场景
                相关产品与服务
                容器服务
                腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档