Singleton模式1
- 格式:docx
- 大小:26.20 KB
- 文档页数:7
python的单例模式--解决多线程的单例模式失效单例模式(Singleton Pattern)是⼀种常⽤的软件设计模式,主要⽬的是确保某⼀个类只有⼀个实例存在。
希望在整个系统中,某个类只能出现⼀个实例时,单例对象就能派上⽤场⽐如,某个服务器程序的配置信息存放在⼀个⽂件中,客户端通过⼀个 AppConfig 的类来读取配置⽂件的信息。
如果在程序运⾏期间,有很多地⽅都需要使⽤配置⽂件的内容,也就是说,很多地⽅都需要创建 AppC 使⽤需求: 程序运⾏起来只需要⼀份⽐如: admin的register数据库连接,数据库连接池(全局变量)全局变量 --- 模块导⼊ (使⽤同⼀个数据)单例模式单例模式的应⽤---数据库连接池class SingleDBpool(object):def __init__(self):self.pool = ...def __new__(cls, *args, **kwargs):if not hasattr(cls,'_instance'):cls._instance = super(SingleDBpool,cls).__new__(*args, **kwargs)return cls._instancedef connect(self):return self.pool.connection()Python1 使⽤模块Python 的模块就是天然的单例模式,因为模块在第⼀次导⼊时,会⽣成 .pyc ⽂件,当第⼆次导⼊时,就会直接加载 .pyc ⽂件,⽽不会再次执⾏模块代码。
因此,我们只需把相关的函数和数据定义在⼀个模块中,就可以获得⼀个单例对象了。
# mysingleton.pyclass My_Singleton(object):def foo(self):passmy_singleton = My_Singleton()将上⾯的代码保存在⽂件 mysingleton.py 中,然后这样使⽤:from mysingleton import my_singletonmy_singleton.foo()2 使⽤ new为了使类只能出现⼀个实例,我们可以使⽤ new 来控制实例的创建过程,代码如下:class Singleton(object):_instance = Nonedef __new__(cls, *args, **kw):if not cls._instance:cls._instance = super(Singleton, cls).__new__(cls, *args, **kw)return cls._instanceclass MyClass(Singleton):a = 13 使⽤类⽅法但是每次调⽤会很繁琐 A.get_instance(params) -- ⽆法⽀持多线程class A(object):instance = Nonedef __init__(self,name): = name@classmethoddef get_instance(cls,*args,**kwargs):if not cls.instance:cls.instance = cls(*args,**kwargs)return cls.instancea = A.get_instance('aaa')b = A.get_instance('bbb')print()多线程下,为什么会失效?import threadingclass Single(object):instance = Nonedef __init__(self):import timetime.sleep(0.5) # 有延时的情况pass@classmethoddef get_instance(cls,*args,**kwargs):if not cls.instance:cls.instance = cls(*args,**kwargs)return cls.instancedef task(arg):obj = Single.get_instance()print(obj)for i in range(5):t = threading.Thread(target=task,args=[i,])t.start()结果:创建了不同的对象 -- 失效# <__main__.Single object at 0x00000000029B8F60># <__main__.Single object at 0x00000000029B8E80># <__main__.Single object at 0x000000000299BD68># <__main__.Single object at 0x00000000029F2BE0># <__main__.Single object at 0x00000000029C2B38>如何解决多线程下单例的失效>> 加线程锁import threadingimport timeclass Single(object):instance = None_threading_lock = threading.Lock()def __init__(self):time.sleep(0.5)@classmethoddef get_instance(cls,*args,**kwargs):if not cls.instance: # 先判断是否存在(如果存在,说明不是多线程,直接获取) with cls._threading_lock: # 加锁,只有⼀个线程进⼊,然后判断单例是否存在 if not cls.instance: # 先判断是否存在(如果存在,说明不是多线程,直接获取) cls.instance = cls(*args,**kwargs)return cls.instancereturn cls.instancedef task(arg):obj = Single.get_instance()print(obj)for i in range(5):t = threading.Thread(target=task,args=[i,])t.start()time.sleep(5)obj = Single.get_instance()print(obj)4 使⽤装饰器可以使⽤装饰器来装饰某个类,使其只能⽣成⼀个实例def Singleton(cls):instance = []def inner(*args,**kwargs):if cls(*args,**kwargs) not in instance:instance.append(cls(*args,**kwargs))return instance[0]return inner@Singletonclass A(object):passa = A()b = A()print(a == b)5 使⽤ metaclass对象和类创建的完整流程:class F:pass1 执⾏type的 init ⽅法(类是type的对象)obj = F()2 执⾏type的 call ⽅法2.1 调⽤ F类的 new ⽅法 (创建对象)2.2 调⽤ F类的 init ⽅法 (对象初始化)obj()3 执⾏ F的 call ⽅法# 继承 type 类(模拟重写 type -- ⽤于创建类)class Single(type):def __init__(self,*args,**kwargs):super(Single,self).__init__(*args,**kwargs)def __call__(cls, *args, **kwargs):obj = cls.__new__(cls,*args, **kwargs)cls.__init__(obj,*args, **kwargs)return obj# ⽤伪type 创建Foo类class Foo(metaclass=Single): # 通过 Single 创建def __init__(self,name):= namedef __new__(cls, *args, **kwargs):return object.__new__(cls,*args, **kwargs)元类(metaclass)可以控制类的创建过程,它主要做三件事:拦截类的创建修改类的定义返回修改后的类使⽤元类实现单例模式:class Single(type): # 通过def __call__(cls, *args, **kwargs):if not hasattr(cls,'_instance'):cls._instance = cls.__new__(cls,*args, **kwargs)return cls._instanceclass Foo(metaclass=Single): # 通过 Single 创建pass这样通过创建Single类,以后需要单例模式的类,可以指定⽤它来创建就可以了Python 的模块是天然的单例模式,这在⼤部分情况下应该是够⽤的,也可以使⽤装饰器、元类等⽅法metaclass补充class MyType(type):def __init__(self, *args, **kwargs):super(MyType, self).__init__(*args, **kwargs)def __call__(cls, *args, **kwargs):return super(MyType, cls).__call__(*args, **kwargs)def with_metaclass(base):return MyType('XX', (base,), {})class Foo(with_metaclass(object)):pass。
Java单例和多例的使用场景1. 引言在Java编程中,单例(Singleton)和多例(Multiton)是两种常用的设计模式。
它们都用于控制对象的创建和访问,但在不同的场景下有不同的应用。
本文将深入探讨Java单例和多例的使用场景,包括对其定义、特点以及适用的具体情况进行详细说明,并举例说明其在实际开发中的应用。
2. 单例模式2.1 定义与特点单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点。
单例模式的主要特点包括:•一个类只有一个实例对象;•类自行实例化,并对外提供访问该实例的静态方法;•防止其他对象创建该类的实例。
2.2 使用场景单例模式适用于以下情况:•系统中只需要一个实例对象,例如配置文件、日志记录器等。
•需要频繁创建和销毁对象的场景,为了节省系统资源,避免频繁的创建和销毁对象,可以使用单例模式。
•需要全局访问点来访问实例对象,例如线程池、数据库连接池等。
2.3 实例应用2.3.1 配置文件读取器在大多数应用程序中,都需要读取配置文件来获取系统配置信息。
使用单例模式可以确保配置文件读取器只有一个实例,避免重复读取配置文件,提高性能。
public class ConfigReader {private static ConfigReader instance;private Properties properties;private ConfigReader() {properties = new Properties();// 读取配置文件try {properties.load(new FileInputStream("config.properties"));} catch (IOException e) {e.printStackTrace();}}public static ConfigReader getInstance() {if (instance == null) {synchronized (ConfigReader.class) {if (instance == null) {instance = new ConfigReader();}}}return instance;}public String getProperty(String key) {return properties.getProperty(key);}}2.3.2 日志记录器在日志记录的场景中,单例模式也经常被使用。
collections.singleton用法1.简介在P yt ho n编程中,`c ol le ct io ns`模块提供了许多有用的数据结构和工具函数,其中之一就是`si ng le to n`。
`s in gl et on`是一种设计模式,它保证一个类只有一个实例,并提供全局访问点。
在本文档中,我们将探讨`co ll ec ti on s.s in gl et on`的用法和一些示例。
2.什么是s ingleto n模式?在软件开发中,s ing l et on模式是一种常用的设计模式。
它确保一个类只能创建一个对象,并提供全局访问点来访问该对象。
使用s i ng le to n模式可以避免创建多个实例,提高资源利用率,并且方便统一管理。
3. co llections.singl eton概述`c ol le ct io ns.s ing l et on`是Py th on`c o ll ec ti on s`模块中的一个函数,用于创建一个只包含一个元素的不可变集合。
它的作用是确保集合中的元素只有一个实例。
`s in gl et on`对象是不可变的,意味着它的值不能被修改。
4.c o llections.singl eton用法示例下面是一个使用`col l ec ti on s.si ng let o n`的简单示例:f r om co ll ec ti on sim p or ts in gl et on创建一个只包含一个元素的集合m y_s in gl et on=s ing l et on(42)输出:{42}尝试修改singleton对象的值会引发异常抛出TypeError: 'singleton' object does not support item assignment在上面的示例中,我们通过调用`si ng le t o n`函数创建了一个只包含一个元素的集合。
Qt中实现单例模式(SingleTon),⼤约有3种办法Qt中实现单例模式(SingleTon)单例模式分为“饥汉”和“饿汉”两种版本,也正是线程安全问题使得原本简单的单例模式变得复杂。
由于单例模式很常⽤,Boost库中有强⼤的泛型单例实现,我也利⽤Qt的原⼦指针QAtomicPointer来实现Qt中的单例模式://.cppclass SingleTon{public:/*! \brief ⽤于获得SingleTon实例,使⽤单例模式。
* \return SingleTon实例的引⽤。
*/static SingleTon &getInstance(void){//使⽤双重检测。
if(!instance)//第⼀次检测{QMutexLocker locker(&mutex);//加互斥锁。
if(!instance)//第⼆次检测。
instance = new SingleTon;}return *instance;}private:SingleTon();//禁⽌构造函数。
SingleTon(const SingleTon &);//禁⽌拷贝构造函数。
SingleTon & operator=(const SingleTon &);//禁⽌赋值拷贝函数。
QReadWriteLock internalMutex;//函数使⽤的读写锁。
static QMutex mutex;//实例互斥锁。
static QAtomicPointer<SingleTon> instance;/*!<使⽤原⼦指针,默认初始化为0。
*/};//静态成员变量初始化。
QMutex SingleTon::mutex;QAtomicPointer<SingleTon> SingleTon::instance = 0;双重锁检测在C++中是安全的,另外提供了读写锁,在修改单例数据的函数中使⽤写锁(QWriteLocker locker(&internalMutex););在读取单例数据的函数中使⽤读锁(QReadLocker locker(&internalMutex);)。
23种设计模式记忆口诀设计模式是软件开发中常见的解决方案模板,它们能够解决许多常见的设计问题。
为了帮助记忆23种设计模式,可以使用下面这个口诀来记忆:Creational Patterns(创建型模式):1. Singleton(单例模式):一个类能产生一个实例,全局访问。
2. Builder(建造者模式):分步骤创建复杂对象,易拓展。
3. Factory Method(工厂方法模式):子类决定实例化哪个对象。
4. Abstract Factory(抽象工厂模式):创建一组相关对象,不依赖具体类。
5. Prototype(原型模式):通过复制现有对象来创建新对象。
Structural Patterns(结构型模式):6. Adapter(适配器模式):将类的接口转换为客户端希望的接口。
7. Bridge(桥接模式):将抽象部分与实际部分分离。
将对象组合成树形结构来表示部分整体的层次结构。
9. Decorator(装饰器模式):动态地给对象添加功能。
10. Facade(外观模式):提供一个统一的接口,简化客户端使用。
11. Flyweight(享元模式):共享细粒度对象,减少内存使用。
12. Proxy(代理模式):控制对其他对象的访问。
Behavioral Patterns(行为型模式):13. Chain Of Responsibility(责任链模式):将请求的发送者和接收者解耦,多个对象都可能处理请求。
将请求封装成对象,可以用参数化方式处理。
15. Iterator(迭代器模式):提供一种遍历集合的统一接口。
16. Mediator(中介者模式):将多个对象之间的复杂关系解耦。
17. Memento(备忘录模式):将对象的状态保存起来,以后可以恢复。
18. Observer(观察者模式):当一个对象改变状态时,依赖它的对象都会收到通知。
19. State(状态模式):对象的行为随状态的改变而改变。
单例模式(C++代码实现)1、先来谈谈什么是单例模式这个单例模式说⽩了就⼀个句话:我是皇帝我独苗看看书上的定义:单例模式(Singleton Pattern)Ensure a class has only one instance, and provide a global point of access to it.(确保⼀个类只有⼀个实例,⽽且⾃⾏实例化并向整个系统提供这个实例)使⽤场景:⼀个系统要求⼀个类只有且仅有⼀个对象,如果出现多个对象就会出现不良反应,可以采⽤单例模式要求⽣成唯⼀序列号在整个项⽬需要⼀个共享访问点或共享数据创建⼀个对象需要消耗的资源过多,如需要访问IO和数据库等资源需要⼤量定义静态常量和静态⽅法(如⼯具类)的环境,当然也可以直接定义为static2、实现思路:既然只能有⼀个实例,那我这个类⾥的构造函数就不能被随便调⽤了,那我就把构造函数写成私有的,这样别⼈就不能调⽤了,接下来就该考虑我⾃⼰这个独苗该怎么产⽣了,定义⾥⾯说到⾃⾏实例化,并且提供给整个系统,那我就⽤⼀个static 实例化⼀个实例,然后返回这个static实例。
3、考虑的问题⼀个实例,整个系统使⽤,那线程同步问题就必须要考虑了。
为了解决这个问题:懒汉模式、饿懒汉模式、Meyers Singleton(⽬前最推荐的C++单例写法)4、代码实现//Meyers Singleton(⽬前最推荐的C++单例写法)#include <iostream>using namespace std;class Singleton{public:static Singleton& Instance(){static Singleton theSingleton;return theSingleton;}void doSomeThong();private:Singleton();~Singleton();};Singleton::Singleton(){}Singleton::~Singleton(){}void Singleton::doSomeThong(){cout << "单例类" << endl;cout << "C++最推荐的单例类写法" << endl;}int main(){Singleton::Instance().doSomeThong();return0;}//懒汉模式:顾名思义,是⼀种典型的拖延(lazy)策略。
hutool singleton用法
Hutool是一个Java工具包,它提供了多个实用的工具类和函数,其中Singleton模式用于保证在程序运行期间,某个类只有一个实例对象。
Hutool提供了多种获取单例对象的方法,下面是部分方法的介绍:
- public static <T> T get(Class<T> clazz, Object... params):获取指定类的单例对象,如果对象存在于池中则返回,否则创建。
每次调用此方法获得的对象为同一个对象。
- public static <T> T get(String key, Func0<T> supplier):获取指定类的单例对象,如果对象存在于池中则返回,否则创建。
每次调用此方法获得的对象为同一个对象。
- public static <T> T get(String className, Object... params):获取指定类的单例对象,如果对象存在于池中则返回,否则创建。
每次调用此方法获得的对象为同一个对象。
在使用Hutool的Singleton模式时,需要注意在项目中引入相应的jar包,并按照工具包的使用规范进行操作。
如果在使用过程中遇到问题,建议查阅相关文档或寻求专业人士的帮助。
Spring中常见的设计模式——单例模式⼀、单例模式的应⽤场景 单例模式(singleton Pattern)是指确保⼀个类在任何情况下都绝对只有⼀个实例,并提供⼀个全局访问点。
J2EE中的ServletContext,ServletContextConfig等;Spring中的ApplicationContext、数据库连接池等。
⼆、饿汉式单例模式 饿汉式单例模式在类加载的时候就⽴即初始化,并且创建单例对象。
它是绝对的线程安全、在线程还没出现以前就实现了,不可能存在访问安全问题。
优点:没有增加任何锁,执⾏效率⾼,⽤户体验⽐懒汉式好。
缺点:类加载的时候就初始化了,⽤不⽤都进⾏,浪费内存。
Spring 中IoC容器ApplocationContext本⾝就是典型的饿汉式单例模式:public class HungrySingleton {private static final HungrySingleton h = new HungrySingleton();private HungrySingleton() {}public static HungrySingleton getInstance() {return h;}} 饿汉式单例模式适⽤于单例对象较少的情况。
三、懒汉式单例模式 被外部调⽤才会加载:public class LazySimpleSingleton {private LazySimpleSingleton() {}private static LazySimpleSingleton lazy = null;public static LazySimpleSingleton getInstance() {if (lazy == null) {lazy = new LazySimpleSingleton();}return lazy;}}利⽤线程创建实例:public class ExectorThread implements Runnable {@Overridepublic void run() {LazySimpleSingleton simpleSingleton = LazySimpleSingleton.getInstance();System.out.println(Thread.currentThread().getName() + ":" + simpleSingleton);}}客户端代码:public class LazySimpleSingletonTest {public static void main(String[] args) {Thread t1 = new Thread(new ExectorThread());Thread t2 = new Thread(new ExectorThread());t1.start();t2.start();System.out.println("END");}}结果:ENDThread-1:zySimpleSingleton@298c37fdThread-0:zySimpleSingleton@6ebc1cfd可以看到产⽣的两个实例的内存地址不同说明产⽣了两个实例,⼤家可以通过以下打断点的⽅式实现不同Thread运⾏状态见进⾏切换。
DCL_单例模式简介单例模式(Singleton Pattern)是 Java 中最简单的设计模式之⼀。
这种类型的设计模式属于创建型模式,它提供了⼀种创建对象的最佳⽅式。
这种模式涉及到⼀个单⼀的类,该类负责创建⾃⼰的对象,同时确保只有单个对象被创建。
这个类提供了⼀种访问其唯⼀的对象的⽅式,可以直接访问,不需要实例化该类的对象。
为什么使⽤单例模式:多个线程操作不同实例对象。
多个线程要操作同⼀对象,要保证对象的唯⼀性优点:1、在内存⾥只有⼀个实例,减少了内存的开销2、避免对资源的多重占⽤单例模式的分类在对⽐每个模式通常往⼀下三个⽅⾯:线程的安全性、性能、懒加载(lazy )1.饿汉式:public class HungerySingleton {//加载的时候就产⽣的实例对象private static HungerySingleton instance=new HungerySingleton();private HungerySingleton(){}//返回实例对象public static HungerySingleton getInstance(){return instance;}public static void main(String[] args) {for (int i = 0; i < 20; i++) {new Thread(()->{System.out.println(HungerySingleton.getInstance());}).start();}}}线程安全性:在加载的时候已经被实例化,所以只有这⼀次,线程安全的懒加载:没有延迟加载,好长时间不使⽤,影响性能性能:性能⽐较好2.懒汉式public class HoonSingleton {private static HoonSingleton instance=null;private HoonSingleton(){}public static HoonSingleton getInstance(){if(null==instance)instance=new HoonSingleton();return instance;}public static void main(String[] args) {for (int i = 0; i < 20; i++) {new Thread(()->{System.out.println(HoonSingleton.getInstance());}).start();}}}线程安全:不能保证实例对象的唯⼀性,⾮线程安全懒加载:引发了⼀个不安全的问题,对于单例模式的应⽤有风险,⽽且风险⽐较⼤,,实现了懒加载性能:相对于饿汉式还是⽐较好的3.懒汉式+同步⽅法线程安全:是线程安全懒加载:是懒加载性能:+synchronized 退化到了串⾏执⾏4.Double-Check-Lockingpublic class DCL {private static DCL instance=null;private DCL(){}public static DCL getInstance(){if(null==instance)synchronized (DCL.class){if(null==instance)instance=new DCL();}return instance;}public static void main(String[] args) {for (int i = 0; i < 20; i++) {new Thread(()->{System.out.println(DCL.getInstance());}).start();}}}性能⽐较好懒加载:实现了懒加载线程的安全性:保证了线程的安全5.Volatile+Double-check只需要加⼀段代码:private volatile static DCL instance=null;可以避免空指针异常6.Holder声明类的时候,成员变量中不声明实例变量,⽽放到内部静态类中public class HolderDemo {private HolderDemo(){}private static class Holder{private static HolderDemo instance=new HolderDemo();}//懒加载//synchronized//<init>public static HolderDemo getInstance(){return Holder.instance;}//⼴泛的⼀种单例模式}7.枚举public class EnumSingletonDemo {private EnumSingletonDemo(){}//延迟加载private enum EnumHolder{INSTANCE;private static EnumSingletonDemo instance=null; private EnumSingletonDemo getInstance(){instance=new EnumSingletonDemo();return instance;}}//懒加载public static EnumSingletonDemo getInstance(){return EnumHolder.INSTANCE.instance;}}。
设计模式实例(Lua)笔记之三(Singleton单例模式)1.描写叙述:这个模式是⾮常有意思,并且⽐較简单,可是我还是要说由于它使⽤的是如此的⼴泛,如此的有⼈缘,单例就是单⼀、独苗的意思,那什么是独⼀份呢?你的思维是独⼀份,除此之外还有什么不能⼭寨的呢?我们举个⽐較难复制的对象:皇帝。
中国的历史上⾮常少出现两个皇帝并存的时期,是有,但不多,那我们就觉得皇帝是个单例模式,在这个场景中,有皇帝,有⼤⾂,⼤⾂是天天要上朝參见皇帝的,今天參拜的皇帝应该和昨天、前天的⼀样(过渡期的不考虑,别找茬哦),⼤⾂磕完头,抬头⼀看,嗨,还是昨天那个皇帝,单例模式,绝对的单例模式,先看类图:凝视:main()。
⼤⾂CEmperor。
须要单例的类说明:⾮常多⼤⾂拜见的皇帝,仅仅有⼀个。
体如今⾯向对象⽅⾯,CEmperor定义⼀个静态指针,和⼀个静态函数,私有化构造函数、析构函数、构造函数复制、重载赋值语句。
注意:线程安全,採⽤相互排斥体的⽅式实现。
2. 代码:Emperor = {}function Emperor:new(o)o = o or {}setmetatable(o,self)self.__index = selfreturn oendfunction Emperor:GetInstance()if self.m_pEmperor == nil thenself.m_pEmperor = self:new()endreturn self.m_pEmperorendfunction Emperor:ReleaseInstance()if self.m_pEmperor thenself.m_pEmperor = nilendendfunction Emperor:EmperorInfo()print("皇帝某年某⽇", os.date("%X", os.time()))end--- main ---function main()pEmperor1 = Emperor:GetInstance()pEmperor1:EmperorInfo()pEmperor2 = Emperor:GetInstance()pEmperor2:EmperorInfo()if pEmperor1 == pEmperor2 thenprint("⼤家都是天天要上朝參见同个皇帝!")endendmain()执⾏结果,例如以下:。
Singleton模式是常用的设计模式之一,但是要实现一个真正实用的设计模式却也不是件容易的事情。
1.标准的实现class Singleton{public:static Singleton * Instance(){if(0== _instance){_instance =new Singleton;}return _instance;}protected:Singleton(void){}virtual~Singleton(void){}static Singleton* _instance;};这是教科书上使用的方法。
看起来没有什么问题,其实包含很多的问题。
下面我们一个一个的解决。
2.自动垃圾回收上面的程序必须记住在程序结束的时候,释放内存。
为了让它自动的释放内存,我们引入auto_ptr改变它。
#include<memory>#include<iostream>using namespace std;class Singleton{public:static Singleton * Instance(){if(0== _instance.get()){_instance.reset(new Singleton);}return _instance.get();}protected:Singleton(void){cout <<"Create Singleton"<<endl;}virtual~Singleton(void){cout <<"Destroy Singleton"<<endl;}friend class auto_ptr<Singleton>;static auto_ptr<Singleton> _instance;};//Singleton.cppauto_ptr<Singleton> Singleton::_instance;3.增加模板在我的一个工程中,有多个的Singleton类,对Singleton类,我都要实现上面这一切,这让我觉得烦死了。
于是我想到了模板来完成这些重复的工作。
现在我们要添加本文中最吸引人单件实现:/*************************************************************** *****(c) 2003-2005 C2217 StudioModule: Singleton.hAuthor: Yangjun D.Created: 9/3/2005 23:17Purpose: Implement singleton patternHistory:**************************************************************** *****/#pragma once#include<memory>using namespace std;using namespace C2217::Win32;namespace C2217{namespace Pattern{template<class T>class Singleton{public:static inline T* instance();private:Singleton(void){}~Singleton(void){}Singleton(const Singleton&){}Singleton &operator=(const Singleton &){}static auto_ptr<T> _instance;};template<class T>auto_ptr<T> Singleton<T>::_instance;template<class T>inline T* Singleton<T>::instance(){if(0== _instance.get()){_instance.reset (new T);}return _instance.get();}//Class that will implement the singleton mode,//must use the macro in it's delare file#define DECLARE_SINGLETON_CLASS( type ) \friend class auto_ptr< type >;\friend class Singleton< type >;}}4.线程安全上面的程序可以适应单线程的程序。
但是如果把它用到多线程的程序就会发生问题。
主要的问题在于同时执行_instance.reset (new T); 就会同时产生两个新的对象,然后马上释放一个,这跟Singleton模式的本意不符。
所以,你需要更加安全的版本:/*************************************************************** *****(c) 2003-2005 C2217 StudioModule: Singleton.hAuthor: Yangjun D.Created: 9/3/2005 23:17Purpose: Implement singleton patternHistory:**************************************************************** *****/#pragma once#include<memory>using namespace std;#include"Interlocked.h"using namespace C2217::Win32;namespace C2217{namespace Pattern{template<class T>class Singleton{public:static inline T* instance();private:Singleton(void){}~Singleton(void){}Singleton(const Singleton&){}Singleton &operator=(const Singleton &){}static auto_ptr<T> _instance;static CResGuard _rs;};template<class T>auto_ptr<T> Singleton<T>::_instance;template<class T>CResGuard Singleton<T>::_rs;template<class T>inline T* Singleton<T>::instance(){if(0== _instance.get()){CResGuard::CGuard gd(_rs);if(0== _instance.get()){_instance.reset (new T);}}return _instance.get();//Class that will implement the singleton mode,//must use the macro in it's delare file#define DECLARE_SINGLETON_CLASS( type ) \friend class auto_ptr< type >;\friend class Singleton< type >;}}CresGuard 类主要的功能是线程访问同步,代码如下:/*************************************************************** ***************Module: Interlocked.hNotices: Copyright (c) 2000 Jeffrey Richter**************************************************************** **************/#pragma once////////////////////////////////////////////////////////////////// /////////////// Instances of this class will be accessed by multiple threads. So,// all members of this class (except the constructor and destructor)// must be thread-safe.class CResGuard {public:CResGuard(){ m_lGrdCnt =0; InitializeCriticalSection(&m_cs);}~CResGuard(){ DeleteCriticalSection(&m_cs);}// IsGuarded is used for debuggingBOOL IsGuarded()const{return(m_lGrdCnt >0);}public:class CGuard {public:CGuard(CResGuard& rg): m_rg(rg){ m_rg.Guard();};~CGuard(){ m_rg.Unguard();}private:CResGuard& m_rg;};private:void Guard(){ EnterCriticalSection(&m_cs); m_lGrdCnt++;}void Unguard(){ m_lGrdCnt--; LeaveCriticalSection(&m_cs);}// Guard/Unguard can only be accessed by the nested CGuard class.friend class CResGuard::CGuard;private:CRITICAL_SECTION m_cs;long m_lGrdCnt;// # of EnterCriticalSection calls};////////////////////////////////////////////////////////////////// /////////////5.实用方法比如你有一个需要实现单件模式的类,就应该这样实现:#pragma once#include"singleton.h"using namespace C2217::Pattern;class ServiceManger{public:void Run(){}private:ServiceManger(void){}virtual~ServiceManger(void){}DECLARE_SINGLETON_CLASS(ServiceManger);};typedef Singleton<ServiceManger> SSManger;在使用的时候很简单,跟一般的Singleton实现的方法没有什么不同。