# 记录两种常用的单例模式 # 第一种
import threading import time class Singleton(object): _instance = None def __init__(self): time.sleep(3) @classmethod def instance(cls, *args, **kwargs): if not cls._instance: cls._instance = cls(*args, **kwargs) return cls._instance # 在多线程时会有问题 s1 = Singleton.instance() s2 = Singleton.instance() print(s1) print(s2)
# 在多线程时,如果在__init__方法中存在IO操作,导致在对象创建过程中出现线程切换,单例模式就会失败。例如,在__init__中加入sleep,再使用多线程创建对象。
def create(): s = Singleton.instance() print(s) for i in range(10): t = threading.Thread(target=create) t.start()
# 输出结果如下:
<__main__.Singleton object at 0x0000022C12E65208> <__main__.Singleton object at 0x0000022C12E65048> <__main__.Singleton object at 0x0000022C12E653C8><__main__.Singleton object at 0x0000022C12E653C8><__main__.Singleton object at 0x0000022C12E653C8><__main__.Singleton object at 0x0000022C12E653C8><__main__.Singleton object at 0x0000022C12E653C8><__main__.Singleton object at 0x0000022C12E5AE48><__main__.Singleton object at 0x0000022C12E5AE48> <__main__.Singleton object at 0x0000022C12E5A978>
# 解决办法加锁:
class Singleton(object): _instance = None _instance_lock = threading.Lock() def __init__(self): time.sleep(3) @classmethod def instance(cls, *args, **kwargs): cls._instance_lock.acquire() if not cls._instance: cls._instance = cls(*args, **kwargs) cls._instance_lock.release() return cls._instance
# 第二种:
# 在创建对象时,先执行__new__方法,因此在__new__方法中实现单例模式,这种方法的好处在于创建对象时和普通创建对象相同
class Singleton(object): _instance = None def __init__(self): time.sleep(2) def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = object.__new__(cls, *args, **kwargs) return cls._instance
s1 = Singleton() s2 = Singleton() print(s1) print(s2)
# 本来以为在使用多线程测试时,会出现和第一种方法相同的问题,但是,测试来看没有发现这个问题,所以也就没有加锁了。