import threading import time event = threading.Event() def cal(name): # 等待事件,進入等待阻塞狀態 print('%s 啟動' % threading.currentThread().getName()) print('%s 準備開始計算狀態' % name) event.wait() # ① # 收到事件後進入執行狀態 print('%s 收到通知了.' % threading.currentThread().getName()) print('%s 正式開始計算!'% name) # 建立並啟動兩條,它們都會①號程式碼處等待 threading.Thread(target=cal, args=('甲', )).start() threading.Thread(target=cal, args=("乙", )).start() time.sleep(2) #② print('------------------') # 發出事件 print('主執行緒發出事件') event.set()上面程式以 cal() 函數為 target,建立並啟動了兩個執行緒。由於 cal() 函數在 ① 號程式碼處呼叫了 Event 的 wait(),因此兩個執行緒執行到 ① 號程式碼處都會進入阻塞狀態;即使主執行緒在 ② 號程式碼處被阻塞,兩個子執行緒也不會向下執行。
Thread-1 啟動
甲 準備開始計算狀態
Thread-2 啟動
乙 準備開始計算狀態
------------------
主執行緒發出事件
Thread-1 收到通知了.
Thread-2 收到通知了.
甲 正式開始計算!
乙 正式開始計算!
Event 實際上優點類似於 Condition 和旗標的結合體,但 Event 本身並不帶 Lock 物件,因此如果要實現執行緒同步,還需要額外的 Lock 物件。
下面是使用 Event 改寫後的 Account:import threading class Account: # 定義構造器 def __init__(self, account_no, balance): # 封裝賬戶編號、賬戶餘額的兩個成員變數 self.account_no = account_no self._balance = balance self.lock = threading.Lock() self.event = threading.Event() # 因為賬戶餘額不允許隨便修改,所以只為self._balance提供getter方法 def getBalance(self): return self._balance # 提供一個執行緒安全的draw()方法來完成取錢操作 def draw(self, draw_amount): # 加鎖 self.lock.acquire() # 如果Event內部旗標為True,表明賬戶中已有人存錢進去 if self.event.is_set(): # 執行取錢操作 print(threading.current_thread().name + " 取錢:" + str(draw_amount)) self._balance -= draw_amount print("賬戶餘額為:" + str(self._balance)) # 將Event內部旗標設為False self.event.clear() # 釋放加鎖 self.lock.release() # 阻塞當前執行緒阻塞 self.event.wait() else: # 釋放加鎖 self.lock.release() # 阻塞當前執行緒阻塞 self.event.wait() def deposit(self, deposit_amount): # 加鎖 self.lock.acquire() # 如果Event內部旗標為False,表明賬戶中還沒有人存錢進去 if not self.event.is_set(): # 執行存款操作 print(threading.current_thread().name + " 存款:" + str(deposit_amount)) self._balance += deposit_amount print("賬戶餘額為:" + str(self._balance)) # 將Event內部旗標設為True self.event.set() # 釋放加鎖 self.lock.release() # 阻塞當前執行緒阻塞 self.event.wait() else: # 釋放加鎖 self.lock.release() # 阻塞當前執行緒阻塞 self.event.wait()