论坛
潜水/灌水快乐,沉淀知识,认识更多同行。
ToB圈子
加入IT圈,遇到更多同好之人。
朋友圈
看朋友圈动态,了解ToB世界。
ToB门户
了解全球最新的ToB事件
博客
Blog
排行榜
Ranklist
文库
业界最专业的IT文库,上传资料也可以赚钱
下载
分享
Share
导读
Guide
相册
Album
记录
Doing
搜索
本版
文章
帖子
ToB圈子
用户
免费入驻
产品入驻
解决方案入驻
公司入驻
案例入驻
登录
·
注册
只需一步,快速开始
账号登录
立即注册
找回密码
用户名
Email
自动登录
找回密码
密码
登录
立即注册
首页
找靠谱产品
找解决方案
找靠谱公司
找案例
找对的人
专家智库
悬赏任务
圈子
SAAS
IT评测·应用市场-qidao123.com技术社区
»
论坛
›
物联网
›
物联网
›
怎样优雅地实现全局唯一?深入理解单例模式 ...
怎样优雅地实现全局唯一?深入理解单例模式
麻花痒
论坛元老
|
4 天前
|
显示全部楼层
|
阅读模式
楼主
主题
1845
|
帖子
1845
|
积分
5535
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要
登录
才可以下载或查看,没有账号?
立即注册
x
怎样优雅地实现全局唯一?深入理解单例模式
一、什么是单例模式?
单例模式是一种创建型设计模式,旨在确保一个类只有一个实例,并为该实例提供全局访问点,从而制止全局变量的命名污染,并支持耽误初始化Wikipedia。
关键点:
私有构造函数(禁止外部new创建)
静态私有实例变量
静态公有获取方法
二、C++实现示例
#include<iostream>
using namespace std;
#if 0
// 饿汉模式 -> 定义类的时候创建单例对象
// 在多线程的场景下没用线程安全问题
// 线程安全:多线程同时访问单例模式
// 定义一个单例模式的任务队列
class TaskQueue
{
public:
TaskQueue(const TaskQueue & t) = delete;
TaskQueue& operator =(const TaskQueue& t) = delete;
static TaskQueue *getInstance()
{
return m_taskQ;
}
void print()
{
cout<<"我是单例对象的一个成员函数..."<<endl;
}
private:
TaskQueue() = default;
// 只能通过类名访问静态成员属性或方法
static TaskQueue* m_taskQ;
};
TaskQueue* TaskQueue::m_taskQ = new TaskQueue;
#endif
#if 1
// 懒汉模式 -> 什么时候使用这个单例,再使用的时候再去创建对应的实例
// 在多线程的场景下可能存在线程安全问题
// 加互斥锁,让线程依次访问单例对象
// 比较节省内存空间
class TaskQueue
{
public:
TaskQueue(const TaskQueue & t) = delete;
TaskQueue& operator =(const TaskQueue& t) = delete;
static TaskQueue *getInstance()
{
if(m_taskQ == nullptr)
{
m_taskQ = new TaskQueue;
}
return m_taskQ;
}
void print()
{
cout<<"我是单例对象的一个成员函数..."<<endl;
}
private:
TaskQueue() = default;
//只能通过类名访问静态成员属性或方法
static TaskQueue* m_taskQ;
};
TaskQueue* TaskQueue::m_taskQ = nullptr;
#endif
int main()
{
TaskQueue* taskQ = TaskQueue::getInstance();
taskQ->print();
return 0;
}
复制代码
懒汉模式利用双重查抄锁定解决线程安全问题
问题原因:
多线程调用懒汉模式
getInstance()
,就会创建出多个
TaskQueue
的实例,违背单例模式的界说,所谓的单例就是只能有唯一的一个单例对象
解决方法:
1、互斥锁解决线程安全问题
互斥锁:制止同时访问,按顺序依次访问
利用原子变量解决双重查抄的问题:
//互斥锁头文件
#include<mutex>
...
mutex TaskQueue::m_mutex;
...
static mutex m_mutex;
...
static TaskQueue *getInstance()
{
if(m_taskQ == nullptr)//第一次检查
{
//进行加锁操作
m_mutex.lock();
if(m_taskQ == nullptr)//第二次检查
{
m_taskQ = new TaskQueue;
}
//进行解锁操作 *注意*一个程序加锁之后一定要解锁,否则导致死锁
m_mutex.unlock();
}
return m_taskQ;
}
...
复制代码
利用原子变量解决双重查抄的问题
//原子变量头文件
#include<atomic>
...
atomic<TaskQueue*> TaskQueue::m_taskQ = nullptr; //初始化
...
static atomic<TaskQueue*>m_taskQ;
...
static TaskQueue *getInstance()
{
TaskQueue* task = m_taskQ.load();
if(task == nullptr)
{
m_mutex.lock();
task = m_taskQ.load();//通过原子变量加载实例化指针
if(task == nullptr)
{
task = new TaskQueue;
m_taskQ.store(task);
}
m_mutex.unlock();
}
return task;
}
...
复制代码
2、局部静态对象解决线程安全问题
// 使用静态的局部对象解决线程安全问题 ->编译器支持C++11
...
class TaskQueue
{
public:
TaskQueue(const TaskQueue & t) = delete;
TaskQueue& operator =(const TaskQueue& t) = delete;
static TaskQueue *getInstance()
{
static TaskQueue task;
return &task;
}
void print()
{
cout<<"我是单例对象的一个成员函数..."<<endl;
}
private:
TaskQueue() = default;
};
...
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复
使用道具
举报
0 个回复
倒序浏览
返回列表
快速回复
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
or
立即注册
本版积分规则
发表回复
回帖并转播
回帖后跳转到最后一页
发新帖
回复
麻花痒
论坛元老
这个人很懒什么都没写!
楼主热帖
【SQL server速成之路】——身份验证及 ...
2022年安装Kali Linux最详细过程,以及 ...
容器开发运维人员的 Linux 操作机配置 ...
ping命令 网络抓包 分析
窄带传输与LoRa扩频传输技术应用方案对 ...
程序员坐牢了,会被安排去写代码吗? ...
我今年12岁了,我喜欢打游戏,怎么能成 ...
密码学奇妙之旅、02 混合加密系统、AES ...
猜
kubectl使用技巧:如何更方便地操作多 ...
标签云
AI
运维
CIO
存储
服务器
浏览过的版块
区块链
快速回复
返回顶部
返回列表