示例
import threading
# 定义全局变量
import time
g_num = 0
class SingletonData(object):
_instance_lock = threading.Lock()
def __new__(cls, *args, **kwargs):
if not hasattr(SingletonData, "_instance"):
with SingletonData._instance_lock:
if not hasattr(SingletonData, "_instance"):
SingletonData._instance = object.__new__(cls)
return SingletonData._instance
def __init__(self,):
pass
mysingleton = SingletonData()
# 循环一次给全局变量加1
def sum_num1(num):
global g_num
for i in range(100000):
lock = mysingleton._instance_lock
flag = lock.acquire(True,)
print("{} num:{} flag:{}".format("sum_num1",g_num,flag))
if flag:
g_num += 1
lock.release()
else:
print("*"*50)
print("sum1:{}::".format(num), g_num)
def sum_num3(num):
global g_num
for i in range(100000):
lock = mysingleton._instance_lock
flag = lock.acquire(True,)
print("{} num:{} flag:{}".format("sum_num3", g_num, flag))
if flag:
time.sleep(0.00000002)
g_num += 1
lock.release()
print("sum1:{}::".format(num), g_num)
# 循环一次给全局变量加1
def sum_num2(mnum):
for i in range(1000000):
global g_num
g_num += 1
print("sum2:", g_num)
if __name__ == '__main__':
# 创建两个线程
first_thread = threading.Thread(target=sum_num1,args=(1,))
second_thread = threading.Thread(target=sum_num3,args=(2,))
# 启动线程
first_thread.start()
# 启动线程
second_thread.start()
print(g_num)
acquire() 方法参数 blocking timeout
语法
acquire( blocking=True, timeout=-1)
blocking
阻塞 :这是一个可选参数,用作阻塞标志。 如果将其设置为True,则如果其他某个线程持有该标志,则调用线程将被阻塞,并且一旦释放该锁,则调用线程将获取该锁并返回True。 如果将其设置为False,则如果其他线程已经获取了锁,它将不会阻塞线程,并且将返回False。 其默认值为True。
timeout
timeout :这是一个可选参数,它指定如果其他某种方法当前正在获取锁,则阻塞调用线程的秒数。 它的默认值是-1,表示线程将无限期地阻塞,直到获得锁为止。
多线程同时操作一个资源 可能会造成混乱
import threading
num = 0
def add1(th):
i = 0
while i <500000:
global num
num +=1
i+=1
print("th{}:".format(th),num)
t1 = threading.Thread(target=add1,args=(1,))
t1.start()
t2 = threading.Thread(target=add1,args=(2,))
t2.start()
运行
th1: 590878
th2: 706512
最终结果不为1000000 错误原因
错误分析:
两个线程first_thread和second_thread都要对全局变量g_num(默认是0)进行加1运算,但是由于是多线程同时操作,有可能出现下面情况:
在g_num=0时,first_thread取得g_num=0。此时系统把first_thread调度为”sleeping”状态,把second_thread转换为”running”状态,t2也获得g_num=0
然后second_thread对得到的值进行加1并赋给g_num,使得g_num=1
然后系统又把second_thread调度为”sleeping”,把first_thread转为”running”。线程t1又把它之前得到的0加1后赋值给g_num。
这样导致虽然first_thread和first_thread都对g_num加1,但结果仍然是g_num=1
全局变量数据错误的解决办法:
线程同步: 保证同一时刻只能有一个线程去操作全局变量 同步: 就是协同步调,按预定的先后次序进行运行。如:你说完,我再说, 好比现实生活中的对讲机
线程同步的方式:
1.线程等待(join)
2. 互斥锁
线程等待(join)
import threading
num = 0
def add1(th):
i = 0
while i <500000:
global num
num +=1
i+=1
print("th{}:".format(th),num)
first_thread = threading.Thread(target=add1,args=(1,))
first_thread.start()
# todo join 会使主线程等待第一个线程执行完成以后代码再继续执行,让其执行第二个线程
# todo 线程同步: 一个任务执行完成以后另外一个任务才能执行,同一个时刻只有一个任务在执行
first_thread.join()
second_thread = threading.Thread(target=add1,args=(2,))
second_thread.start()
运行结果
th1: 500000
th2: 1000000