Lock機制通常會使用於,當有多個線程要使用同一個代碼資源,且對同一個全域(共享)變數進行修改的時候。
例如當有多個線程要使用同一段程式碼資源時,若不想要在使用期間被其他線程拿來同時使用,此時就可以用 鎖(Lock) 的機制來確保資源一次只給一個線程運行。
假如今天有一間廁所(function)和一把鑰匙(threading.Lock()
),有很多的人(threads)都在排隊要大號,先到的人(thread)就可以獲得廁所門的鑰匙(lock),並且在上廁所的時候會把門鎖起來(lock.acquire()
),此時正在排隊的其他人就只能在門外等待,直到正在大號的人把門打開將鑰匙交出來(lock.release()
),這樣下一個人就能拿到這鑰匙進入廁所,並把門鎖起來以防止他人進入,以此類推~
創建一個lock對象: lock = threading.Lock()
獲取使用lock: lock.acquire()
解除釋放lock: lock.release()
import threading
import time
lock = threading.Lock() # 廁所門的鑰匙(lock)
toilet = [] # 放屎的馬桶(list)
# 廁所(function)
def WC():
lock.acquire() # 使用鑰匙將廁所門上鎖
toilet.append(f"{threading.current_thread().name}: 拉了第1坨屎") # 將當前的人(線程)所拉的第一屎放進馬桶(list)中
time.sleep(0.1)
toilet.append(f"{threading.current_thread().name}: 拉了第2坨屎") # 將當前的人(線程)所拉的第二屎放進馬桶(list)中
lock.release() # 將廁所門解鎖, 並把鑰匙放在旁邊等下一個人來拿
# 產生3位排隊大號的人
for i in range(3):
wc_thread = threading.Thread(target=WC)
wc_thread.start() # 第 i 個人開始進廁所大號
time.sleep(1) # 等待一秒確保三個人都上完廁所, 且馬桶內都有他們排放的屎了
print(toilet) # 將馬桶內的屎打印出來看排序
['Thread-1: 拉了第1坨屎', 'Thread-1: 拉了第2坨屎', 'Thread-2: 拉了第1坨屎', 'Thread-2: 拉了第2坨屎', 'Thread-3: 拉了第1坨屎', 'Thread-3: 拉了第2坨屎']
['Thread-1: 拉了第1坨屎', 'Thread-2: 拉了第1坨屎', 'Thread-3: 拉了第1坨屎', 'Thread-1: 拉了第2坨屎', 'Thread-3: 拉了第2坨屎', 'Thread-2: 拉了第2坨屎']
由此可知,有使用Lock的馬桶(list)結果會是:
先等第一個人(Thread-1)拉完兩坨屎後,第二位(Thread-2)和第三位(Thread-3)才會接續繼續。
反之,不使用Lock的馬桶(list)結果會是:
第一個人(Thread-1)才剛拉完第一坨屎,都還沒拉完第二坨,第二位(Thread-2)和第三位(Thread-3)就一起進來各拉了第一坨屎,後續也一起拉了第二坨,等於現在這間廁所內同時有三個人在拉屎。
當有多個執行緒同時執行lock.acquire()
時,只有一個執行緒能成功獲取到鎖,並且繼續執行程式碼,其他的執行緒就只能等待直到鎖被釋放並獲得為止。