多一个线程同时运行,有时线程之间需要共享数据,一个线程需要其他线程的数据,否则就不能保证程序运行结果的正确性。
多个线程间共享的数据称为共享资源或临界资源,由于是CPU负责线程的调度,程序员无法精确控制多线程的交替顺序。这种情况下,多线程对临界资源的访问有时会导致数据的不一致性。
可以为这些资源对象加上一把“互斥锁”,在任一时刻只能由一个线程访问,即使该线程出现阻塞,该对象的被锁定状态也不会解除,其他线程仍不能访问该对象,这就是多线程同步。线程同步保证线程安全的重要手段,但是线程同步客观上会导致性能下降。
对于简单线程同步可以使用threading模块的Lock类,Lock对象有两中状态:“锁定”和“未锁定”,默认是“未锁定”状态,Lock对象有两个方法acquire()和release()实现锁定和解锁,acquire()方法可以实现锁定,使得Lock对象进入“锁定”;release()方法可以实现解锁,使得Lock对象进入“未锁定”。
下图的例子为模拟两个购票网点的购票情况:
import threading
import time
class TicketDB:
def __init__(self):
self.ticket_count=5
def get_ticket_count(self):
return self.ticket_count
def sell_ticket(self):
#线程休眠等待用户付款
time.sleep(1)
print('当前线程为{0}'.format(threading.current_thread().name))
print('第{0}号票已经售出'.format((self.ticket_count)))
self.ticket_count-=1
db=TicketDB()
lock=threading.Lock()
def thread1_body():
global db
global lock
while True:
lock.acquire()
curr_ticket_count=db.get_ticket_count()
if curr_ticket_count>0:
db.sell_ticket()
else:
lock.release()
break
lock.release()
time.sleep(1)
def thread2_body():
global db
global lock
while True:
lock.acquire()
curr_ticket_count = db.get_ticket_count()
if curr_ticket_count > 0:
db.sell_ticket()
else:
lock.release()
break
lock.release()
time.sleep(1)
def main():
t1=threading.Thread(target=thread1_body)
t1.start()
t2=threading.Thread(target=thread2_body)
t2.start()
if __name__ == '__main__':
main()