单例模式:用来创建独一无二的,只能够有一个实例的对象。 单例模式的结构是设计模式中最简单的,但是想要完全实现一个线程安全的单例模式还是有很多陷阱的,所以面试的时候属于一个常见的考点~

单例模式的应用场景:有一些对象其实只需要一个,比如:线程池,缓存,对话框,处理偏好设置和注册表的对象,日志对象,充当打印机,显卡等设备的驱动程序对象。这些对象只能够拥有一个实例,如果创建出了多个实例,就会导致一些程序的问题。程序的行为异常,资源使用的过量,或者导致不一致的结果。常用来管理共享的资源,比如数据库的连接或者线程池。

单例模式的类图非常简单,如下~,并且经典的实现也非常的简单。

class Singleton {
public:
static Singleton* getInstance();
//析构的时候释放资源~
~Singleton() {
if( (_instance != NULL)
delete _instance;
}
protected:
Singleton();
private:
static Singleton* _instance;
} Singleton *Singleton::_instance = NULL;
Singleton* Singleton::getInstance() {
if( _instance == NULL) {
_instance = new Singleton();
}
return _instance;
}

经典的实现非常容易,但是存在一个问题,就是这个经典的实现非线程安全,多线程的情况下,这个单例模式的实现会出现问题~,如何解决呢?改进!

class Lock
{
private:
mutex mtex;
public:
Lock(mutex m) : mtex(m)
{
mtex.Lock();
}
~Lock()
{
mtex.Unlock();
}
};
class Singleton {
public:
static Singleton* getInstance();
//析构的时候释放资源~
~Singleton() {
if( (_instance != NULL)
delete _instance;
}
protected:
Singleton();
private:
static Singleton* _instance;
static mutex m;
} Singleton *Singleton::_instance = NULL;
Singleton* Singleton::getInstance() {
//check 之前进行临界区加锁操作
Lock lock(m);
if( _instance == NULL) {
_instance = new Singleton();
}
return _instance;
}

线程安全保证的一种方法及为在check _instance == NULL 之前进行临界区加锁,如果已经有一个线程进入访问,其他线程必须等待,这样就能够保证多线程情况下实例的唯一!

but,互斥的同步会导致性能的降低,即使_instance已经不为空了,每次还是需要加锁,这样操作花费就比较多,性能必定比较差。

另外还有一些比较好的方法:

1.(非线程同步的方法)上面的操作均为一种lazy initialization的思想,及用到的时候在初始化,这样程序效率比较高,但是有一个另外比较好的方法可以采用是提前初始化,将_instance设置为static之后直接初始化为Singleton对象,每次只需要执行返回操作即可。

这样的话同样会导致问题,就是如果单例本来资源比较多,但是不需要创建那么早,就会消耗资源~。

class Singleton {
public:
static Singleton* getInstance();
//析构的时候释放资源~
~Singleton() {
delete _instance;
}
protected:
Singleton();
private:
static Singleton* _instance;
} Singleton *Singleton::_instance = new Singleton();
Singleton* Singleton::getInstance() {
return _instance;
}

2.另外一种提升因为同步导致的性能变差的方法称为“双重检验加锁”。方法如下:

思路是只有在第一次创建的时候进行加锁,当_instance不为空的时候就不需要进行加锁的操作,这样就可以提升性能~

class Lock
{
private:
mutex mtex;
public:
Lock(mutex m) : mtex(m)
{
mtex.Lock();
}
~Lock()
{
mtex.Unlock();
}
};
class Singleton {
public:
static Singleton* getInstance();
//析构的时候释放资源~
~Singleton() {
if( (_instance != NULL)
delete _instance;
}
protected:
Singleton();
private:
static Singleton* _instance;
static mutex m;
} Singleton *Singleton::_instance = NULL;
Singleton* Singleton::getInstance() {
//check 之前进行临界区加锁操作
//双重检验加锁
if(_instance == NULL ) {
Lock lock(m);
if( _instance == NULL) {
_instance = new Singleton();
}
}
return _instance;
}

总之,小小单例模式问题还是挺多的,面试官喜欢问的一个问题~,因为还是有很多陷阱的。

单例模式全面学习(C++版)的更多相关文章

  1. Learning ROS for Robotics Programming - Second Edition(《ROS机器人编程学习-第二版》)

    Learning ROS for Robotics Programming - Second Edition <ROS机器人编程学习-第二版> ----Your one-stop guid ...

  2. 软件开发常用设计模式—单例模式总结(c++版)

    单例模式:就是只有一个实例. singleton pattern单例模式:确保某一个类在程序运行中只能生成一个实例,并提供一个访问它的全局访问点.这个类称为单例类.如一个工程中,数据库访问对象只有一个 ...

  3. c#.net单例模式的学习记录!

    一. 单例(Singleton)模式 单例模式的特点: 单例类只能有一个实例. 单例类必须自己创建自己的唯一实例. 单例类必须给所有其它对象提供这一实例. 单例模式应用: 每台计算机可以有若干个打印机 ...

  4. 单例模式总结(Java版)

    1:懒汉的设计模式,在第一次调用的时候才完成相关的初始化操作 懒汉式是典型的时间换空间,就是每次获取实例都会进行判断,看是否需要创建实例,浪费判断的时间.当然,如果一直没有人使用的话,那就不会创建实例 ...

  5. IOS 单例模式的学习

    单例模式只能修改无法释放,直到程序结束. 我们下面一步一步来做一个单例模式程序 (1)单例一旦创建,是永远存在于内存中的,所以需要创建一个全局量 static MySingletonClass *sh ...

  6. HTML学习3---排版标记

    上节,我们学习了boda常用的属性以及HTML的一些标记,但是图显示的效果却不是那么的好看. 原因就是没有排版好,我们这次使用居中来使这个页面更好看一点,顺便多加入几个别的标记. HTML排版标记 ( ...

  7. word2vec学习 spark版

    参考资料: http://ir.dlut.edu.cn/NewsShow.aspx?ID=291 http://www.douban.com/note/298095260/ http://machin ...

  8. -sql语句练习50题(Mysql学习练习版)

    –1.学生表 Student(s_id,s_name,s_birth,s_sex) –学生编号,学生姓名, 出生年月,学生性别 –2.课程表 Course(c_id,c_name,t_id) – –课 ...

  9. .NET单例模式快速学习应用

    单例模式属于设计模式中最简单的一个模式,在实际应用中也非常广泛,但可能是受到各类教程的影响,看到很多实现方式仍然沿用Java的那一套,其实在.NET中可以用更简洁的实现方式. 一.知识点介绍 核心目标 ...

随机推荐

  1. 阿里云mysql远程连不上

    1. 服务器规则添加 3306端口 2. mysql localhost 改为% mysql> select user, host from mysql.user; GRANT ALL PRIV ...

  2. 解决win8.1电脑无法安装手机驱动问题

    相信安装过win8.1的朋友都会有个问题,那就是自己的安卓手机怎么都连不上电脑,比如360助手.豌豆荚.91助手,都安不上驱动.下面几个简单步骤即可轻松解决. 1.首先声明,官方的驱动是完全支持win ...

  3. css段落首字母下沉

    摘要: 段落首字母放大是指放大段落开头的字母或者汉字,主要使用了css的first-letter伪类选择器. 单行放大: 在第一行内放大,效果如下: <!DOCTYPE html> < ...

  4. Chrome扩展应用

    现在越来越多的用户将chrome浏览器设置为自己默认的浏览器,不仅是因为他的界面美,最重要的是他对html5和CSS3完美的支持,且调试工具非常好用,还有丰富的扩展库.如何安装自己的扩展呢? 点击自定 ...

  5. [scala] scala 集合(⑧)

    1.List 基础操作 2.Set 基础操作 3. TreeSet 排序Set 4. 拉链操作 5. 流 import scala.collection.immutable.TreeSet impor ...

  6. OC中Runtime浅析

    近期了解了一下OC的Runtime,真的是OC中非常强大的一个机制,看起来比較底层,但事实上能够有非常多活用的方式. 什么是Runtime 我们尽管是用Objective-C写的代码,事实上在运行过程 ...

  7. spring mvc处理方法返回方式

    Model: package org.springframework.ui; import java.util.Collection; import java.util.Map; public int ...

  8. iframe设置高度为100%

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. 关于openssl的编译与使用

    关于openssl的编译与使用,可以参考这两往篇文章 http://blog.csdn.net/lazyclough/article/details/7456131 http://www.leaves ...

  10. c 网络字节序和本机字节序转换

    将多字节整数类型的数据,从主机的字节顺序转化为网络字节顺序 #include <netinet/in.h> uint32_t htonl(uint32_t hostlong);uint16 ...