上一篇文章講述的互斥鎖是簡單的線程同步機(jī)制,但對于復(fù)雜線程同步問題的支持無法很好的滿足。因此本篇文章引入條件同步變量肥照。Condition除了能提供RLock()和Lock()的方法外,還提供了 wait()秋麸、notify()袖外、notifyAll()方法循头。希望感興趣的小伙伴可以堅持看下去同時歡迎提出寶貴的意見讓我們一起進(jìn)步唠摹!
01:條件同步變量(Condition)
1)概述:在滿足了特定的條件后,線程才可以訪問相關(guān)的數(shù)據(jù)爆捞。
2)原理:線程首先acquire一個條件變量,然后判斷一些條件。如果條件不滿足則wait ; 如果條件滿足,進(jìn)行一些處理改變條件后通過notify方法通知其他線程 ; 其他處于wait狀態(tài)線程接到通知后會重新判斷條件
3)調(diào)用方式:cond =threading.Condition(Lock/RLock);不傳默認(rèn)RLock
4)常用方法:
①wait(timeout):線程掛起,等待直到收到一個notify通知或出現(xiàn)超時才會被喚醒繼續(xù)運(yùn)行勾拉。
②notify(n):喚醒一個或多個等待此條件變量的線程煮甥。
③notifyAll():喚醒所有等待此條件的線程。
5)使用場景:生產(chǎn)者與消費(fèi)者問題,一個線程生產(chǎn)的數(shù)據(jù)提供給另外一個線程使用藕赞。
6)注意事項:
①wait()成肘、notify()、notifyAll()方法必須在已獲得Lock前提下才能調(diào)用,否則會觸發(fā)RuntimeError斧蜕。
②調(diào)用wait()會釋放Lock,直至該線程被Notify()双霍、NotifyAll()或者超時線程又重新獲得Lock。
③如果存在多個線程等待同一個條件,notify()操作會喚醒他們中的一個或多個(這種行為取決于底層的操作系統(tǒng))
④notify()不會主動釋放Lock
02:案例操作
早點(diǎn)鋪的師傅必須蒸好包子,消費(fèi)者才能把包子買來吃掉批销。即:
生產(chǎn)者可以不斷生產(chǎn)商品直到倉庫裝滿然后告知消費(fèi)者消費(fèi);
消費(fèi)者也可以判斷倉庫是否滿從而告知生產(chǎn)者繼續(xù)生產(chǎn)商品洒闸。
import threading,time,random
lock_con=threading.Condition()#條件鎖對象
num_list=[]#創(chuàng)建一個空列表
def producer():
global num_list#引用全局變量
while True:#模擬不停的生產(chǎn)包子
if lock_con.acquire():#上鎖
num_list.append(1)
print('生產(chǎn)者:','生產(chǎn)了一個包子',num_list)
lock_con.notifyAll()#通知等待池激活所有線程
lock_con.release()#解鎖
time.sleep(random.randint(0,10)*0.1)#模擬包子端上桌的時間
def consumer():
global num_list
while True:#模擬不停的吃掉包子
if lock_con.acquire():#上鎖
if len(num_list)==0:
print('包子已賣完,請等待包子生產(chǎn)中!!!')
lock_con.wait()#線程釋放鎖進(jìn)入等待,被喚起重新加鎖
num_list.remove(num_list[0])#去掉第一個元素
print('消費(fèi)者:','吃掉了一個包子',num_list)
time.sleep(random.randint(0,10)*0.2)#模擬吃掉包子的時間
lock_con.notifyAll()
lock_con.release()#解鎖
t1=threading.Thread(target=producer)
t2=threading.Thread(target=consumer)
t1.start()
t2.start()
t1.join()
t2.join()