1、基于模块引用(饱汉模式)
建立文件Emperor_Singleton.py,内容如下:
# 皇帝类
class Emperor(object):
def say(self):
print('我是唯一的皇帝!')
emperor = Emperor()
测试内容如下:
from singleton.Emperor_Singleton import emperor
emperor.say()
运行测试类,打印结果:
我是唯一的皇帝!
2、基于__new__方法,继承父单例类(饿汉模式, __new__方法类似其他语言的构造函数)
建立文件Singleton.py,内容如下(父单例类):
class Singleton:
__instance = None
def __new__(cls, *args, **kwargs):
if Singleton.__instance is None:
Singleton.__instance = object.__new__(cls, *args)
return Singleton.__instance
测试内容如下:
import random
from singleton.Singleton import Singleton
class Emperor(Singleton):
def __init__(self):
if not hasattr(self, 'name'):
self.name = random.choice(['秦始皇', '汉武帝', '康熙', '汉献帝'])
def say(self):
print('我是皇帝:', self.name, ',我的id:', id(self))
for i in range(10):
Emperor().say()
运行测试类,打印结果:
我是皇帝: 汉献帝 , 我的id: 4330069576
我是皇帝: 汉献帝 , 我的id: 4330069576
我是皇帝: 汉献帝 , 我的id: 4330069576
我是皇帝: 汉献帝 , 我的id: 4330069576
我是皇帝: 汉献帝 , 我的id: 4330069576
我是皇帝: 汉献帝 , 我的id: 4330069576
我是皇帝: 汉献帝 , 我的id: 4330069576
我是皇帝: 汉献帝 , 我的id: 4330069576
我是皇帝: 汉献帝 , 我的id: 4330069576
我是皇帝: 汉献帝 , 我的id: 4330069576
3、基于__new__方法的线程安全性
上面第2点基于__new__方法,存在线程安全问题。我们实验下,将Singleton类创建对象的时间延长,如下:
class Singleton:
__instance = None
def __new__(cls, *args, **kwargs):
if Singleton.__instance is None:
for i in range(5000000):
continue
Singleton.__instance = object.__new__(cls, *args)
return Singleton.__instance
测试文件创建10个线程,如下:
import random
import threading
from singleton.Singleton import Singleton
class Emperor(Singleton):
def __init__(self):
if not hasattr(self, 'name'):
self.name = random.choice(['秦始皇', '汉武帝', '康熙', '汉献帝'])
def say(self):
print('我是皇帝:', self.name, ', 我的id:', id(self))
class MyThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
Emperor().say()
if __name__ == '__main__':
threads = []
for i in range(10):
threads.append(MyThread())
for t in threads:
t.start()
for t in threads:
t.join()
运行测试类,打印结果:
我是皇帝: 汉武帝 , 我的id: 4330917960
我是皇帝: 康熙 , 我的id: 4330918016
我是皇帝: 秦始皇 , 我的id: 4330917960
我是皇帝: 秦始皇 , 我的id: 4330918016
我是皇帝: 秦始皇 , 我的id: 4330917960
我是皇帝: 汉献帝 , 我的id: 4330918016
我是皇帝: 秦始皇 , 我的id: 4330917960
我是皇帝: 秦始皇 , 我的id: 4330918016
我是皇帝: 秦始皇 , 我的id: 4330917960
我是皇帝: 秦始皇 , 我的id: 4330918016
可以看出,这里显然是线程不安全的……
4、编写线程安全的饿汉单例,基于__new__方法
修改Singleton类,加入双重锁机制:
import threading
class Singleton:
__instance = None
__lock = threading.Lock()
def __new__(cls, *args, **kwargs):
if Singleton.__instance is None:
Singleton.__lock.acquire()
if Singleton.__instance is None:
for i in range(5000000):
continue
Singleton.__instance = object.__new__(cls, *args)
Singleton.__lock.release()
return Singleton.__instance
还是用上面的测试文件,结果如下:
我是皇帝: 康熙 , 我的id: 4330938552
我是皇帝: 康熙 , 我的id: 4330938552
我是皇帝: 康熙 , 我的id: 4330938552
我是皇帝: 康熙 , 我的id: 4330938552
我是皇帝: 康熙 , 我的id: 4330938552
我是皇帝: 康熙 , 我的id: 4330938552
我是皇帝: 康熙 , 我的id: 4330938552
我是皇帝: 康熙 , 我的id: 4330938552
我是皇帝: 康熙 , 我的id: 4330938552
我是皇帝: 康熙 , 我的id: 4330938552