单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。单例模式同时也是所有设计模式中最简单的一种。
那么问题来了,单例类有什么作用呢?对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。
如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机。
简单来说。单例模式就是说系统中对于某类的只能有一个对象,不可能出来第二个。下面以模板的形式实现两种单例类,基于模板通用性会更好,否则对于每个类都要实现自己的单例模式:

#include <iostream>
#include <pthread.h>
#include <unistd.h>
using namespace std;
//单例类模板
template <class T>
class Singleton
{
public:Singleton()//可放在private{}static T* instance()//返回某类型的单例对象{if(m_pInstance == NULL)//这里进行了两遍检查{pthread_mutex_lock(&mutex);//上锁if(m_pInstance == NULL)//保证只能执行一次{T* temp = new T;//构造一个新的对象m_pInstance = temp;}pthread_mutex_unlock(&mutex);//解锁}return m_pInstance;//返回该类型的单例对象}
private:static T* m_pInstance;static pthread_mutex_t mutex;//需要互斥锁
};template<class T>T* Singleton<T>::m_pInstance = NULL;template<class T>
pthread_mutex_t Singleton<T>::mutex;class Test:public Singleton<Test>
{//使用继承的方式
public:Test(){cout<<"我只会打印一次"<<endl;}
};void* thread1(void*)//第一组线程的线程函数
{cout<<"thread1 正在运行"<<endl;Test* test1 = Test::instance();//调用该函数,但是Test对象只会创建一次
}void* thread2(void *)//第二组线程的线程函数
{cout<<"thread2 正在运行"<<endl;Test* test2 = Test::instance();//调用该函数,但是Test对象只会创建一次
}
int main()
{const unsigned int thread_num = 5;pthread_t thread_id[thread_num];for(unsigned int i = 0; i<thread_num;i++)//创建1组5个线程{pthread_create(&thread_id[i], NULL, thread1, NULL);}for(unsigned int i = 0; i<thread_num;i++)//创建另一组的五个线程{pthread_create(&thread_id[i], NULL, thread2, NULL);}sleep(1);//等待线程结束return 0;
}

该程序分两次分别创建了5个线程,在每个线程中分别调用Test::instance()获取单例类对象,两个线程线程函数会分别运行5次,但是对象只会构造一次,其余的并没有构造新的对象,只是返回该对象而已,运行结果如下:

在linux中其实还有一种更加方便的方式,这也是muduo库里面的实现方式(muduo库的实现大家可以直接取看源码,其实和下面的大同小异),因为linux里为我们提供了pthread_once函数,这种单例模式比较通用,而且在多线程环境下也很稳定,该函数原型如下:

#include <pthread.h>int pthread_once(pthread_once_t *once_control,void (*init_routine)(void));pthread_once_t once_control = PTHREAD_ONCE_INIT;

pthread_once函数第一个参数是一个pthread_once_t类型的变量,该变量可以保证init_routine函数只被执行一次,所以使用该函数会使单例类的实现变得简单许多,看下面的例子

#include <iostream>
#include <pthread.h>
#include <unistd.h>
using namespace std;
template<class T>
class Singleton
{
public:static T& instance()//返回单例类对象{//原型是int pthread_once(pthread_once_t *once_control,void (*init_routine)(void));//init_routine函数只可能被执行一次pthread_once(&m_Once, &Singleton::init);return *m_tValue;}
private:Singleton();//构造函数~Singleton();//析构函数static void init()//该函数只被执行一次{m_tValue = new T();//在内部创建的对象}
private:static pthread_once_t m_Once;//该对象保证某个函数只被执行一次static T* m_tValue;
};template<typename T>
pthread_once_t Singleton<T>::m_Once = PTHREAD_ONCE_INIT;template<typename T>T* Singleton<T>::m_tValue = NULL;class Test
{
public:Test(){cout<<"虽然创建了10个线程,但是我只会打印一次"<<endl;}
};void* thread_func(void*)
{cout<<"thread_func正在执行"<<endl;Test& t = Singleton<Test>::instance();//创建一个Test类型的单例对象
}
int main(int argc, char const *argv[])
{pthread_t thread_id[10];for(int i=0;i<10;i++)//创建10个线程{pthread_create(&thread_id[i], NULL, thread_func, NULL);//在每个线程的线程函数里创建Test单例对象}sleep(1);//稍作延时等待线程结束return 0;
} 

该程序和第一个例子实现的功能差不多,不过只是这次一次性创建10个线程,运行结果和之前的大同小异

单例模式及单例类的两种实现相关推荐

  1. 理解单例模式、单例类

    在大部分时候,我们把类的构造器定义成public访问权限,允许任何类自由创建该类的对象.但是在某些时候,允许其他类自由创建该类的对象没有任何意义,还可能造成系统性能下降(因为创建一个对象的系统开销问题 ...

  2. c++实现单例类(懒汉与饿汉)

    教科书里的单例模式 我们都很清楚一个简单的单例模式该怎样去实现:构造函数声明为private或protect防止被外部函数实例化,内部保存一个private static的类指针保存唯一的实例,实例的 ...

  3. java中单例设计模式登记式单例类_java23种设计模式-创建型模式之单例模式

    单例模式(Singleton) 单例对象(Singleton)是一种常用的设计模式.在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在.这样的模式有几个好处: 1.某些类创建比较频 ...

  4. Java单例模式详解--七种单例模式实现+单例安全+实际应用场景

    单例模式 保证了一个类只有一个实例,并且提供了一个全局访问点.单例模式的主要作用是节省公共资源,方便控制,避免多个实例造成的问题. 实现单例模式的三点: 私有构造函数 私有静态变量维护对象实例 公有静 ...

  5. Android学习-Kotlin语言入门-变量、函数、语法糖、when、for-in、主构造函数、单例类、函数式API、集合遍历、隐式Intent、Activity生命周期、四种启动模式、标准函数

    探究java语言的运行机制 变量.函数.语法糖 when条件语句 for循环 主构造函数.次构造函数 数据类和单例类 集合的创建与遍历 集合的函数式API 创建菜单 隐式使用Intent Activi ...

  6. 单例模式(Python中的单例类)

    目录 一.单例模式的概述 二.单例模式的优缺点 三.在Python中,单例模式有以下几种实现方式 1.通过魔法方法__new__实现 2.通过模块的导入 3.通过装饰器实现 4.通过使用类实现 一.单 ...

  7. struts单例模式 java_Java单例设计模式详细介绍

    Java单例设计模式教程中包含了单例模式的定义.特点以及线路安全等问题. 单例模式定义: 单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例.在计算机系统中,线程池.缓存.日志对象 ...

  8. 设计模式详解:Singleton(单例类)

    Singleton(单例类) 设计模式学习:概述 意图 保证每一个类仅有一个实例,并为它提供一个全局访问点. 顾名思义,单例类Singleton保证了程序中同一时刻最多存在该类的一个对象. 有些时候, ...

  9. java 防止反射_如何防止JAVA反射对单例类的攻击?

    在我的上篇随笔中,我们知道了创建单例类有以下几种方式: (1).饿汉式; (2).懒汉式(.加同步锁的懒汉式.加双重校验锁的懒汉式.防止指令重排优化的懒汉式); (3).登记式单例模式; (4).静态 ...

最新文章

  1. 【原创】腾讯微博的XSS攻击漏洞
  2. 辛东方:科技的发展将导致更多人失业?
  3. 首次结算和汇总不一致
  4. prestashop后台如何删除订单
  5. MyEclipse 使用文档
  6. 如何下载微信开发者工具?
  7. 如何解决使用PCS7时报警无法确认的问题?
  8. 西门子PLC编写抢答系统
  9. 常见反爬虫方法及其应对策略
  10. 西安电子科技大学计算机学院评论,西电高琳教授团队在Science子刊及领域著名期刊发表成果...
  11. linux-xfce4-panel
  12. STM32显示图片,将图片转换为十六进制数组便捷工具
  13. Android 系统服务
  14. php 微信红包接龙源码_PHP生成微信红包
  15. 【人工智能 Open AI】解释一下 Raft 分布式一致性协议算法,并用伪代码实例说明。
  16. 2022年博士招生 | 华南理工大学-鹏城实验室 联培博士 专项计划
  17. ROS2学习笔记(3)什么是ROS2 topics
  18. [汇总]Flex面试题及答案
  19. 艺赛旗RPA离线识别普通验证码
  20. everbox邀请码和麦库邀请码

热门文章

  1. testflight怎么做版本更新_苹果更新 TestFlight 3.0 版本:能自动更新内测应用了
  2. 微信小游戏 -- unhandled promise rejection 解决办法
  3. 财经365独家:基建物业投资路线图
  4. Mac家谱制作软件MacFamilyTree 9好用吗?如何在MacFamilyTree 9中创建数据库的备份?
  5. python逐笔输入数据_知到智慧树Python数据分析与数据可视化结课测验
  6. c语言托儿所收2到6岁儿童,2018下教师资格考试测试试题:幼儿《保教知识与能力》(三)...
  7. Cookies 和 session
  8. python中的pickle是什么意思_python中pickle模块浅析
  9. 谷歌手机pixel4 夜景_如何在Google Pixel手机上使用实时字幕
  10. 《生命科学50讲》课程笔记10-自由意志