关键点:饿汉式、懒汉式、线程安全、线程单例
单例模式(Singleton Pattern)是最简单的设计模式,属于创建型模式
解决的根本问题:保证这个类有且只有一个实例对象,并且提供全局获取入口。比如 对文件的读写需要统一一个对象去管理
单例模式有哪些使用场景呢
- 访问资源冲突:比如读写同一个文件,使用单例可以只加对象级别的锁就可以
- 全局唯一:配置文件之类的,同一个窗体不重复创建两次
基本套路是私有化构造方法、提供getInstance方法获取实例。下面为单例模式的几种写法以及优缺点
饿汉式
饿汉式为在代码运行的时候,就创建出来这个对象,调取getInstance方法,就可以获取这个对象
python中的饿汉式可以直接在文件中创建对象,外部引用通过import的方式调用
class Singleton:
def __init__(self):
pass
singleton = Singleton()
外部引用
from Singleton import singleton
饿汉式的使用场景是 如果创建对象比较耗时,在调用其他的时候依赖这个类的创建,会导致这个方法的性能瓶颈是在这个类的创建上。而饿汉式单例,是在项目运行时就创建好对象,避免此问题。
注意网上流传的饿汉式的写法,我认为不是真正的饿汉式,下面我附上代码和我的理解
class Singleton(object):
_instance = None
def __new__(cls, *args, **kwargs):
import time
time.sleep(10)
if not hasattr(Singleton, '_instance'):
cls._instance = super(Singleton, cls).__new__(cls)
return cls._instance
这样写,是满足了在调用初始化函数init之前创建对象,但是他还是在调用init的时候,触发生成这个对象,这样还是会在第一次调用其他方法的时候,出现创建此对象延迟的问题,因此我认为这种写法不是饿汉式。
懒汉式
饿汉式为调用getInstance方法时,再去创建类返回,最大的优点是延迟加载
class SingletonByLazy(object):
"""
线程安全的懒汉式单例模式
"""
_instance_lock = threading.Lock()
@staticmethod
def get_instance():
if not hasattr(SingletonByLazy, "_instance"):
with SingletonByLazy._instance_lock:
if not hasattr(SingletonByLazy, "_instance"):
SingletonByLazy._instance = SingletonByLazy(*args, **kwargs)
return SingletonByLazy._instance
这里因为线程安全和性能的考虑,检测了两次hasattr(SingletonByLazy, "_instance")
单例模式的问题
有时候,像id生成器,直接调用getId方法就好了,没必要获取那个对象
会隐藏依赖、继承关系
对代码的扩展性不够好
延伸问题
- 线程唯一的单例模式:通过字典,key为线程id,value为对象,以此保证线程唯一
- 进程、集群唯一的单例模式:通过文件来创建对象,保证文件的来保证数据唯一(java可以通过二进制文件来创造对象?待验证)
- 多例模式
未完成事项
- 线程安全的示意图
- java、go代码实现
- java通过文件创建类