单例模式 (Singleton Pattern)

单例模式 (Singleton Pattern) 是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点。

一、基础

1. 意图

  • 确保一个类只有一个实例。
  • 提供一个全局访问点。

2. 适用场景

  • 一个类只需要一个实例来协调系统行为时,例如数据库连接池,线程池、缓存、日志对象等。
  • 需要控制实例数目,节省系统资源,避免重复创建和浪费, 同时保证数据的一致性和正确性。

3. 结构

  • 一个静态成员变量
  • 一个私有构造函数
  • 一个静态方法

二、进阶

1. 线程安全

  • 饿汉式: 在类加载时就创建实例,线程安全,但可能会造成资源浪费。
  • 懒汉式: 在第一次调用 getInstance() 时才创建实例,需要考虑线程安全问题。
  • 双重检查锁定: 使用 volatile 关键字和 synchronized 关键字来保证线程安全。
  • 静态内部类: 利用类加载机制保证线程安全。

2. 序列化与反序列化

  • 在 C++ 中,并没有像 Java 那样内置的序列化机制。但是,如果使用第三方库(如 Boost.Serialization)进行序列化和反序列化操作,同样需要注意单例模式的问题。在反序列化时,可能会创建新的实例对象,破坏单例模式。为了避免这种情况,可以在反序列化过程中进行特殊处理,确保返回的是已经存在的单例实例。

3. 反射攻击

  • 为了防止反射调用私有构造函数创建新的实例,可以在构造函数中进行判断。

三、关键点

1. 私有构造函数:单例类的构造函数必须是私有的,以防止外部通过new关键字实例化对象,确保只有一个实例对象存在。

2. 静态实例变量:单例类中必须有一个静态的实例变量来保存唯一的实例对象,并且该实例变量的作用域必须是私有的,以防止外部直接访问和修改。

3. 公共静态访问方法:提供一个公共的静态方法,作为全局访问点,用于获取单例对象的实例。该方法通常命名为getInstance()。

4. 线程安全:在多线程环境下,单例模式的实现必须保证线程安全,确保在任何情况下都只会创建一个实例对象。常见的线程安全实现方式有同步方法、双重检查锁定、静态局部变量等。

5. 延迟加载:对于某些应用场景,延迟加载(懒汉式)是非常重要的,它可以避免在程序启动时就创建不必要的实例对象,从而提高系统性能和资源利用率。但需要注意的是,懒汉式实现需要处理好线程安全问题。

四、易错点

1. 线程安全问题:在实现懒汉式单例模式时,如果不注意线程安全,很容易导致在多线程环.          境下创建多个实例对象,违反单例模式的定义。例如,在没有同步机制的情况下,多个线程同时.   调用getInstance()方法,并且此时instance为nullptr,就会创建多个实例对象。

2. 序列化与反序列化:当使用第三方库进行序列化和反序列化操作时,如果不处理好单例模式的问题,可能会导致在反序列化时创建新的实例对象,破坏单例模式。需要在反序列化过程中进行特殊处理,确保返回的是已经存在的单例实例。

3. 反射破坏:虽然 C++ 没有像 Java 那样强大的反射机制,但是通过一些技术手段也可以实现类似反射的功能。如果不小心使用这些技术调用了单例类的私有构造函数,同样会破坏单例模式。为了防止这种情况,需要在构造函数中添加逻辑判断,防止重复创建实例对象。

4. 指令重排:在使用双重检查锁定实现线程安全的懒汉式单例模式时,需要注意编译器和处理器的指令重排问题。虽然 C++11 标准中引入了内存模型来解决这个问题,但是在一些老版本的编译器或者特定的硬件平台上,仍然可能存在指令重排导致的线程安全问题。

五、核心代码

1. 饿汉式

饿汉式是单例模式中最简单的一种实现方式。在程序启动时,就立即创建唯一的实例对象,并且该实例对象是静态的,因此在程序的整个生命周期中只会存在一个实例。

优点:实现简单,线程安全,因为在程序启动时就创建了实例,不存在多线程并发创建的问题。

缺点:如果该单例对象在整个应用程序中不一定会被使用到,那么在程序启动时就创建实例可能会造成资源浪费。

class Singleton {
private:
    static Singleton* instance;
    Singleton() {} // 私有构造函数

public:
    static Singleton* getInstance() {
        return instance;
    }
};

Singleton* Singleton::instance = new Singleton(); // 类加载时创建实例

2. 懒汉式 (双重检查锁定)

双重检查锁定(Double-Checked Locking)是一种优化的线程安全懒汉式实现方式。它通过两次检查instance是否为nullptr,在保证线程安全的同时提高了性能。

优点:延迟加载,只有在真正需要使用单例对象时才创建,避免了不必要的资源浪费。既实现了线程安全,又提高了性能。在第一次检查instance为nullptr时,只有一个线程能够进入同步块,在同步块内再次检查instance为nullptr时才创建实例对象,避免了每次调用getInstance()方法都获取锁的性能开销。

缺点:实现相对复杂,需要理解双重检查锁定的原理以及互斥锁的使用。

class Singleton {
private:
    static Singleton* instance;
    static std::mutex mtx;
    Singleton() {} // 私有构造函数

public:
    static Singleton* getInstance() {
        if (instance == nullptr) {
            std::lock_guard<std::mutex> lock(mtx);
            if (instance == nullptr) {
                instance = new Singleton();
            }
        }
        return instance;
    }
};

Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

3. 懒汉式 (静态内部类)

在 C++11 之后,可以利用静态局部变量的特性来实现单例模式,这种方式既实现了延迟加载,又保证了线程安全。

优点:延迟加载,线程安全。由于静态局部变量在第一次调用getInstance()方法时才会被初始化,因此实现了延迟加载。同时,C++11 标准保证了静态局部变量的初始化是线程安全的。

缺点:无明显缺点。

class Singleton {
private:
    Singleton() {} // 私有构造函数

    static class SingletonHolder {
    public:
        static Singleton* instance;
    };

public:
    static Singleton* getInstance() {
        return SingletonHolder::instance;
    }
};

4. 防止序列化与反序列化

class Singleton {
private:
    static Singleton* instance;
    Singleton() {} // 私有构造函数

public:
    static Singleton* getInstance() {
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }

    // 防止反序列化创建新的实例
    Singleton* readResolve() {
        return getInstance();
    }
};

Singleton* Singleton::instance = nullptr;

5. 防止反射攻击

class Singleton {
private:
    static Singleton* instance;
    Singleton() {
        if (instance != nullptr) {
            throw std::runtime_error("Singleton instance already exists!");
        }
    } // 私有构造函数

public:
    static Singleton* getInstance() {
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }
};

Singleton* Singleton::instance = nullptr;

六、总结

单例模式是一种常用的设计模式,但需要注意线程安全、序列化与反序列化、反射攻击等问题。在实际开发中,需要根据具体需求选择合适的实现方式。

设计模式之单例模式(七种方法超详细) 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象,也就是说不能使用new关键字来创建对象。 阅读详情

相关推荐

单例模式介绍

目录 1 前言 2 单例模式类型 2.1 饿汉式: 2.2 懒汉式: 2.2.1 双重检查锁 2.2.2volatile防止指令重排 2.3 静态内部类 3 破坏单例 1 前言 单例模式是指在内存中有且只会创建一次对象的设计模式,在程序中多次使用同一个对象且作用相同的时候,为了防止频繁的创建对象,单例模式可以让程序在内存中创建一个对象,让所有的调用者都共享这一单例对象。单例模式的类型有两种:懒汉式和饿汉式。 2 单例模式类型 饿汉式:在类加载的时候已经创建好该单例对象。 懒汉.

爪哇人的博客 7938

单例模式(Singleton Pattern)

单例模式是一种设计模式,确保一个类只有一个实例,并提供全局访问点。本文介绍了单例模式的两种实现方式:饿汉模式和懒汉模式。饿汉模式在程序启动时就创建实例,线程安全但可能浪费资源;懒汉模式在首次调用时创建实例,C++11后线程安全且更节省资源。文章详细解析了两种模式的代码实现、核心特点及适用场景,并对比了它们的优缺点。单例模式适用于需要全局唯一对象的场景,如配置管理、线程池等。建议根据实际需求选择实现方式,确保代码效率和安全性。

祯的博客 1489

达梦数据库与sharding-jdbc的深度适配实践

本文详细介绍了达梦数据库与sharding-jdbc的深度适配实践,包括驱动与依赖管理、核心适配实现、注册与配置等关键步骤。通过扩展shardingSphere的方式,成功实现了达梦数据库的分库分表功能,并提供了常见问题解决方案和性能优化建议,助力企业级应用高效处理海量数据。

weixin_30300225的博客 623

PHP服务端 苹果支付(IAP)处理

公司做的app需要做IAP订阅支付,开始觉得和微信的支付流程差不多,做起来还是有点麻烦,主要是网上的文章很少,不能拿来主义。自己做完总结一下,希望对小伙伴们有帮助我就很欣慰了。代码写的不好 不要喷我。。。 首先讲一下我的业务逻辑,也就是php服务端需要做什么事情。 先上图: 下面我详细的讲一下每...

山水的博客 1万+

伯德图详解:从传递函数到系统稳定性的频域分析

在自动控制与控制系统设计中,理解系统对不同频率输入信号的响应特性,是分析和设计稳定系统的核心基础。频率响应描述了系统对正弦输入的幅值增益与相位变化规律,而伯德图作为最直观的频域分析工具,通过对数坐标将宽频带特性压缩成一条清晰曲线,让工程师无需复杂计算即可快速评估系统性能。从典型环节的渐近线绘制,到相位裕度、幅值裕度的读取,伯德图贯穿了系统稳定性判断、控制器参数整定及噪声抑制等关键场景。本文结合实际调试经验,系统讲解伯德图的绘制原理与读图方法,帮助读者快速掌握从传递函数到工程应用的核心技能。

weixin_34535286的博客 334

【Android】条形码/二维码扫描——ZXing源码分析

正在更新中 针对3.2.1版本源码 与其他版本代码可能会有出入,但核心思想基本不变。 首先从com.google.zxing.client.android包中的目录结构分析:Book:这个文件夹中有5个类: BrowseBookListener 实现了adapter的点击事项响应,通过获取ISBN,然后跳转到Google books中查询响应的详细信息。 SearchBookContents

年轻的学徒 2453

SSH 远程登录报错:kex_exchange_identification: Connection closed.....

不知道为啥会出现这样的情形,最近这段时间登录都是正常的,不知道哪里抽风了,就提示这个。错误信息 kex_exchange_identification: Connection closed by remote host 出现在尝试使用 SSH 连接到远程服务器过程中,表明在密钥交换阶段的一开始,远程主机就关闭了连接。服务器的sshd_config文件中配置错误,可能是不允许的加密算法、修订文件中的语法错误,或者未正确指定用于SSH的HostKey。如果当前已有太多活动连接,新的连接尝试可能会被拒绝。

飞越蓝天的专栏 8296

TensorFlow2深度学习实战(十四):目标检测算法 YOLOv4 解析

最易上手的【计算机视觉】小白教程!

不积跬步,无以至千里! 7631

从HCI层浅析LE Audio通话建立流程

本文分析了BLE AUDIO通话协议建立的全过程。当手机来电时,系统会通过CCP EATT链路通知耳机准备通话,并断开原有音乐CIS连接。随后建立通话专用的CIG组,其参数设置(如MAX SDU SIZE=80、RTN=2)与音乐场景明显不同,更注重通话的实时性。文中详细描述了设置ISO数据路径、启用ASE、建立CIS连接等关键步骤,特别指出通话采用Conversational音频上下文类型。最后解析了ISO数据包参数含义,展示了10ms周期、32kHz采样率等通话特性参数。整个过程体现了BLE AUDIO

十多年蓝牙协议软件开发,擅长蓝牙协议分析 1860

WOFOST作物模型(3):敏感性分析

使用TAGP(Total Above Ground Production),地上总产量TSUM1,temperature sum from emergence to anthesis,萌发至开花所需温度TSUM2,temperature sum from anthesis to maturity,开花至成熟所需温度SPAN,life span of leaves growing at 35 Celsius,生长温度为35度时的叶龄。

所有专家都曾始于新手 1145

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

上一篇: CoreML 与Vision
下一篇: 工厂方法模式 (Factory Method Pattern)
直隶码农
博客等级 码龄19年 95粉丝 103原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值