我们课程中的讲解的单例对象,不是线程安全的,当多个线程同时去创建对象的时候,就会出现问题。
回答
whit回答
一、首先,复习下课程中的讲解的单例对象的代码。
class Person(object):
__instance = None
__init_flag = False
def __new__(cls,name):
if cls.__instance == None:
cls.__instance = object.__new__(cls)
return cls.__instance
else:
return cls.__instance
def __init__(self,name):
if Person.__init_flag == False:
self.name = name
Person.__init_flag = True
二、使用 10个线程来创建对象。
from threading import Thread
import random
import time
class Person(object):
__instance = None
__init_flag = False
def __new__(cls,name):
if cls.__instance == None:
time.sleep(random.random()) #这里 需要加延时,产生线程不安全的效果,不然看不到效果。
cls.__instance = object.__new__(cls)
return cls.__instance
else:
return cls.__instance
def __init__(self,name):
if Person.__init_flag == False:
self.name = name
Person.__init_flag = True
def test_thread():
"""打印单例对象的id"""
print(id(Person("小明")))
if __name__ == '__main__':
for i in range(10):
Thread(target=test_thread).start()
三、在__new__方法中加上线程锁
from threading import Thread,Lock
import random
import time
m = Lock()
class Person(object):
__instance = None
__init_flag = False
def __new__(cls,name):
if cls.__instance == None:
time.sleep(random.random())
m.acquire()
cls.__instance = object.__new__(cls)
m.release()
return cls.__instance
else:
return cls.__instance
def __init__(self,name):
if Person.__init_flag == False:
self.name = name
Person.__init_flag = True
def test_thread():
"""打印单例对象的id"""
print(id(Person("小明")))
if __name__ == '__main__':
for i in range(10):
Thread(target=test_thread).start()
测试结果:
此时加了锁之后,发现 没有作用,依然是线程不安全的。问题出在哪里?
假设1号线程在随机延时的时候,发生了线程调度,切换到了2号线程开始执行,2号线程随机延时的时间比较短,把所有的代码执行完了,创建了对象a,打印到屏幕。
2号线程结束之后,1号线程继续执行,又创建了一个对象b。导致了 线程不安全。
四、在加锁之后,再去判断 __instance 这个类属性,也就是说 要判断两次。
from threading import Thread,Lock
import random
import time
m = Lock()
class Person(object):
__instance = None
__init_flag = False
def __new__(cls,name):
if cls.__instance == None:
time.sleep(random.random())
m.acquire()
if cls.__instance == None:
cls.__instance = object.__new__(cls)
m.release()
return cls.__instance
else:
return cls.__instance
def __init__(self,name):
if Person.__init_flag == False:
self.name = name
Person.__init_flag = True
def test_thread():
"""打印单例对象的id"""
print(id(Person("小明")))
if __name__ == '__main__':
for i in range(10):
Thread(target=test_thread).start()
执行代码 发现,程序 卡主了。。为什么呢?
如果第二次判断 __instance 的时候,__instance 不是None 呢,就不会释放锁了。。那其他线程也就得不到锁了。
五. 最终代码
from threading import Thread,Lock
import random
import time
m = Lock()
class Person(object):
__instance = None
__init_flag = False
def __new__(cls,name):
if cls.__instance == None:
time.sleep(random.random())
m.acquire()
if cls.__instance == None:
cls.__instance = object.__new__(cls)
m.release()
return cls.__instance
else:
return cls.__instance
def __init__(self,name):
if Person.__init_flag == False:
self.name = name
Person.__init_flag = True
def test_thread():
"""打印单例对象的id"""
print(id(Person("小明")))
if __name__ == '__main__':
for i in range(10):
Thread(target=test_thread).start()
结果测试:
ok,成功了。。。
(1)