单例模式
一个类仅有一个实例,并提供一个全局访问点,该实例被所有程序模块共享。
Java基于ClassLoader机制确保类只被实例化1次。多线程安全,没有加锁,类加载时初始化,浪费内存。
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
Java基于枚举类的常量确保类只被实例化1次(实际上枚举常量在内部都转化为枚举类的实例)。多线程安全,支持序列化机制,非Lazy初始化。
public enum Singleton {
INSTANCE;
public void whateverMethod() {
}
}
Python利用类地址和类变量的全局唯一性确保类只被实例化1次(实例变量不是全局唯一的)。
Python类(class)通过__new__()
创造实例(instance),继承并修改__new__()
方法,检验类变量。
class Singleton(object):
_instance = None
def __new__(cls, *args, **kw): # 类实例化时的传参可以接收到,默认参数接收不到
if cls._instance is None:
cls._instance = object.__new__(cls)
return cls._instance
def __init__(self):
pass
single1 = Singleton()
single2 = Singleton()
print(id(single1) == id(single2))
使用Python函数装饰器,检验类变量。
def singleton(cls):
_instance = {}
def func():
if cls not in _instance:
_instance[cls] = cls()
return _instance[cls]
return func
@singleton
class Cls(object):
def __init__(self):
pass
cls1 = Cls()
cls2 = Cls()
print(id(cls1) == id(cls2))
使用Python函数装饰器,检验类变量。
class Singleton(object):
def __init__(self, cls):
self._cls = cls
self._instance = {}
def __call__(self):
if self._cls not in self._instance:
self._instance[self._cls] = self._cls()
return self._instance[self._cls]
@Singleton
class Cls2(object):
def __init__(self):
pass
cls1 = Cls2()
cls2 = Cls2()
print(id(cls1) == id(cls2))
C++中static对象的初始化
non-local static对象(函数外)。初始化发生在main函数执行之前,也即main函数之前的单线程启动阶段,所以不存在线程安全问题。但C++没有规定多个non-local static 对象的初始化顺序,尤其是来自多个编译单元的non-local static对象,他们的初始化顺序是随机的。
local static 对象(函数内)。初始化发生在控制流第一次执行到该对象的初始化语句时。多个线程的控制流可能同时到达其初始化语句。C++11之前,在多线程环境下local static对象的初始化并不是线程安全的。C++11规定,在一个线程开始local static 对象的初始化后到完成初始化前,其他线程执行到这个local static对象的初始化语句就会等待,直到该local static 对象初始化完成。
class Singleton
{
private:
Singleton() { };
~Singleton() { };
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
public:
static Singleton& getInstance()
{
static Singleton instance;
return instance;
}
};