创建型模型-单例模式

本文详细介绍了单例模式的概念、角色和职责,包括懒汉式和饿汉式的实现。通过C++代码展示了这两种方式,并通过测试函数演示了它们在多线程环境下的行为。在多线程环境中,懒汉式单例可能出现问题,而饿汉式则表现良好。为了解决懒汉式在多线程环境下的线程安全问题,引入了双检锁(double-checked locking)来确保单例的正确创建。
摘要由CSDN通过智能技术生成

  单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。

单例模式中的角色和职责

在这里插入图片描述
Singleton(单例):在单例类的内部实现只生成一个实例,同时它提供一个静态的getInstance()工厂方法,让客户可以访问它的唯一实例;为了防止在外部对其实例化,将其构造函数设计为私有;在单例类内部定义了一个Singleton类型的静态对象,作为外部共享的唯一实例。
如何构建单例:
一是单例模式的类只提供私有的构造函数,
二是类定义中含有一个该类的静态私有对象,
三是该类提供了一个静态的公有的函数用于创建或获取它本身的静态私有对象。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

/* 懒汉式 */
class Chairman_lazy 
{
private:
	Chairman_lazy() {}
public:
	static Chairman_lazy* getInstance() 
	{
		if (s_singleton == NULL) 
		{
			s_singleton = new Chairman_lazy;
		}
		return s_singleton;
	}
private:
	static Chairman_lazy* s_singleton;
};
Chairman_lazy* Chairman_lazy::s_singleton = nullptr;


void test01() 
{

	Chairman_lazy* chairman1 = Chairman_lazy::getInstance();
	Chairman_lazy* chairman2 = Chairman_lazy::getInstance();
	if (chairman1 == chairman2) 
	{
		cout << "指向同一个对象!" << endl;
	}
	else 
	{
		cout << "指向不是同一个对象!" << endl;
	}

}

/* 饿汉式 */
class Chairman_hangry 
{
private:
	Chairman_hangry() {}
public:
	static Chairman_hangry* getInstance() 
	{
		return s_singleton;
	}
private:
	static Chairman_hangry* s_singleton;
};

//初始化
Chairman_hangry* Chairman_hangry::s_singleton = new Chairman_hangry;

void test02() {

	Chairman_hangry* chairman1 = Chairman_hangry::getInstance();
	Chairman_hangry* chairman2 = Chairman_hangry::getInstance();
	if (chairman1 == chairman2) {
		cout << "指向同一个对象!" << endl;
	}
	else {
		cout << "指向不是同一个对象!" << endl;
	}
}

int main() {

	test01();
	test02();

	system("pause");
	return EXIT_SUCCESS;
}

注意:静态变量必须在类外进行初始化,否则编译不过

饿汉式还可以使用静态变量得方式:

class Lazy
{
private:
	Lazy() {}
public:
	static Lazy* getInstance()
	{
		static Lazy lazy;
		return &lazy;
	}
};

int main()
{
	Lazy *pLazy = Lazy::getInstance();
	Lazy *pLazy2 = Lazy::getInstance();
	cout << pLazy << endl;
	cout << pLazy2 << endl;
	return 0;
} 

单例碰到多线程

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<Windows.h>
using namespace std;

/* 懒汉式 */
class Chairman_lazy 
{
private:
	Chairman_lazy() {}
public:
	static Chairman_lazy* getInstance() 
	{
		if (s_singleton == NULL) {
			//Sleep(1000); //等到1000秒
			s_singleton = new Chairman_lazy;
		}
		return s_singleton;
	}
private:
	static Chairman_lazy* s_singleton;
};

Chairman_lazy* Chairman_lazy::s_singleton = NULL;


/* 饿汉式 */
class Chairman_hangry 
{
private:
	Chairman_hangry() {}
public:
	static Chairman_hangry* getInstance() 
	{
		return s_singleton;
	}
private:
	static Chairman_hangry* s_singleton;
};

//初始化
Chairman_hangry* Chairman_hangry::s_singleton = new Chairman_hangry;

DWORD WINAPI MyThread_hangry(LPVOID lpThreadParameter)
{

	Chairman_hangry* chairman = Chairman_hangry::getInstance();
	cout << "单例对象地址:" << (int*)chairman << endl;

	return 0;
}

//饿汉式单例碰到多线程测试
void test01() 
{

	HANDLE handler[10];
	for (int i = 0; i < 10; i++) 
	{
		handler[i] = CreateThread(NULL, NULL, MyThread_hangry, NULL, NULL, NULL);
	}

}

DWORD WINAPI MyThread_lazy(LPVOID lpThreadParameter) 
{

	Chairman_lazy* chairman = Chairman_lazy::getInstance();
	cout << "单例对象地址:" << (int*)chairman << endl;

	return 0;
}

//懒汉式单例碰到多线程
void test02() 
{

	HANDLE handler[10];
	for (int i = 0; i < 10; i++) 
	{
		handler[i] = CreateThread(NULL, NULL, MyThread_lazy, NULL, NULL, NULL);
	}

}

int main() {

	//test01();
	test02();

	system("pause");
	return EXIT_SUCCESS;
}

Test01函数执行结果(饿汉式单例模式):
在这里插入图片描述
Test02函数执行结果(懒汉式单例模式):
在这里插入图片描述
从结果可以看出,饿汉式多线程环境没有问题,而懒汉式多线程环境会存在问题,主要时由于在判断对象为空时可能多个线程都进来了导致多次new对象,解决这种方式的问题就是加锁。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<Windows.h>
#include <mutex>
using namespace std;

/* 懒汉式 */
class Chairman_lazy 
{
private:
	Chairman_lazy() {}
public:
	static Chairman_lazy* getInstance() 
	{
		if (s_singleton)
			return s_singleton;
		  // 双重检查锁定
        if (s_singleton == NULL) {
            m_mutex.lock();
            if (s_singleton == NULL) {
                //Sleep(1000); //等到1000秒
                s_singleton = new Chairman_lazy;
            }
            m_mutex.unlock();
        }
		return s_singleton;
	}
private:
	static Chairman_lazy* s_singleton;
	static mutex m_mutex;
};

Chairman_lazy* Chairman_lazy::s_singleton = NULL;
mutex Chairman_lazy::m_mutex;

单例模式的优缺点

优点:
(1)单例模式提供了对唯一实例的受控访问。
(2)节约系统资源。由于在系统内存中只存在一个对象。

缺点:
(1) 扩展略难。单例模式中没有抽象层。
(2) 单例类的职责过重。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

vegetablesssss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值