箴理

一个追求技术和内涵的求学者

  • 主页
  • 所有文章
所有文章 友链 关于我

箴理

一个追求技术和内涵的求学者

  • 主页
  • 所有文章

单例模式浅谈

2017-05-15

单例模式几种实现方式

单例模式作为设计模式中最简单,应用最广泛的一个,熟练掌握该设计模式无论对于面试还是项目使用,想来是极好的。最近也是看面试题的时候看到了这块,发现自己忘的都差不多了,又重新熟悉了下,并且综合网上各种混杂的实现方式以及四人帮的《设计模式》,把几种单例模式的关系捋清,并且给出自己的解答

总体呢,单例模式有两种,一种是懒汉,一种是饿汉,这两种是实现单例模式的不同思路。第一种呢,就是“懒”嘛,只有具体使用这个实例的时候才会去实例化。那饿汉则反之,程序一开始就实例化。

那明显呢,上述两者有自己的优缺点。懒汉的优点就是实例创建延迟至真正使用的时候,无疑对内存效率使用较高。但是缺点是不具有线程安全性,也就是说不做一些处理就不能适应多线程;饿汉的优点则是具有线程安全性,因为在程序运行一开始即在主线程已经实例化好了。但缺点则是内存效率较低。简单来说,懒汉是以时间换空间;饿汉是以空间换时间。

最简单的懒汉实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//类定义
class Singleton
{
public:
static Singleton* GetInstance()
{
if(m_Instance == NULL)
{
m_Instance = new Singleton();
}
return m_Instance;
}
protected: Singleton(){}
private:
static Singleton *m_Instance;
}
//初始化
Singleton *Singleton::m_Instance = nullptr;
//使用时
Singleton *obj=Singleton::GetInstance();

该实现方式是最简单的单例模式,但带来的问题是 不具有线程安全性,当多线程环境下,会实例化多个对象。所以就引申出下一个多线程模式。

懒汉多线程加锁实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//类定义
class Singleton
{
public:
static Singleton* GetInstance()
{
Lock();//具体实现可以采用boost库,或者用mutex变量
if(m_Instance == NULL)
{
m_Instance = new Singleton();
}
UnLock();
return m_Instance;
}
protected: Singleton(){}
private:
static Singleton *m_Instance;
}

我们采用加锁的方式,因为一个时刻只有一个线程能得到锁,所以可以解决多线程问题。但是仔细分析又有一个问题,那就是每次去getInstance()时都会去加上一个锁,而加锁是一个很耗时的操作,所以在没必要的时候要避免去加锁。这就是下一个改进版的double-check。

懒汉多线程加锁改进实现(double-check)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//类定义
class Singleton
{
public:
static Singleton* GetInstance()
{
if(m_Instance == NULL)//前后两次判断,这样可以大大减少不必要的加锁操作
{
Lock();
if(m_Instance == NULL)
{
m_Instance = new Singleton();
}
UnLock();
}
return m_Instance;
}
protected: Singleton(){}
private:
static Singleton *m_Instance;
}

这种写法提高了效率,但是实现起来比较复杂而且容易出错。下来推荐更加优秀的写法。

懒汉最简洁实现(局部静态变量)

1
2
3
4
5
6
7
8
9
10
11
12
13
//类定义
class Singleton
{
public:
static Singleton& GetInstance()
{
static Singleton m_Instance;
return m_Instance;
}
protected: Singleton(){}
}
//使用时
Singleton *obj=Singleton::GetInstance();

最简洁,没有之一。c++11标准可以保证局部静态变量的线程安全性,所以这种方式不仅简洁,而且不用考虑其他实现方式还要考虑的delete过程,所以非常推荐这种方法,不过这个也有一个不适用的地方,对于打印机,加锁的文件等并不是在不用的时候就delete掉,而是必须在程序结束时delete 的场景,这个实现方式就无法解决了。而饿汉的一种改进形式可以完美解决这个问题(通过内嵌一个static的类)。

饿汉实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//类定义
class Singleton
{
public:
static const Singleton* GetInstance()
{
return m_Instance;
}
protected: Singleton(){}
private:
static const Singleton *m_Instance;
}
//静态初始化
const Singleton *Singleton::m_Instance = new Singleton();
//使用时
Singleton *obj=Singleton::GetInstance();

由于在程序开始时即以静态初始化的方式 主线程完成了初始化,所以可以保证线程安全性。在性能要求比较高时,采用这种方式,可以避免频繁的加锁和解锁造成的资源浪费。

饿汉自动销毁实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//类定义
class Singleton
{
public:
static Singleton* GetInstance()
{
return m_Instance;
}
protected: Singleton(){}
private:
static Singleton *m_Instance;
class GC
{
public:
~GC()
{
if(m_Instance != NULL)
{
delete m_Instance;
m_Instance=NULL;
}
}
}
static GC gc;
}
//初始化
Singleton *Singleton::m_Instance = new Singleton();
Singleton ::GC Singleton ::gc;
//使用时
Singleton *obj=Singleton::GetInstance();

在程序运行结束后,系统会对静态存储区的变量释放,这就包括全局变量以及类的静态成员变量(这里是同等对待的),我们定义了Singleton私有的类GC来实现最终释放我们的实例。释放静态变量gc时,调用其析构函数~GC(),在这里实现了对m_Instance的释放。

总结

以上几种单例模式的实现都有其特点,根据实际场景可能会有所结合或者改动。目前来说c++的所有单例模式实现原理思路就是上述几种啦。其实还有一种更吊的方式,既能按需创建实例(即懒汉),又能自动释放,又很简洁。那就是c#的静态构造函数。具体实现机制自行百度。

转载请注明出处

赏

谢谢你请我吃糖果

支付宝
微信
  • 设计模式

扫一扫,分享到微信

微信分享二维码
Cocos2d-x基础知识
© 2017 箴理
Hexo Theme Yilia by Litten
  • 所有文章
  • 友链
  • 关于我

tag:

  • 游戏编程
  • 设计模式
  • python 爬虫
  • cocos2d

    缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    3、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: false
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true
    

  • 军
  • 友情链接2
  • 友情链接3
  • 友情链接4
  • 友情链接5
  • 友情链接6
LZ