1. 程式人生 > >跟我學程式碼架構設計模式之--鎖和執行緒

跟我學程式碼架構設計模式之--鎖和執行緒

上篇講到鎖可以用來解決多執行緒同時訪問同一資源時的同步問題,即鎖可以控制多執行緒對函式關聯資源的的同步訪問。這一篇我來簡單分析下鎖如何解決同步問題的。

在講鎖之前,我們我們先來討論下wait和notify方法,這兩個方法是用來控制執行緒執行的。說白了就是控制執行緒狀態的流轉,wait控制執行緒本身掛起等待到某個物件的阻塞佇列中,執行緒由就緒或執行態轉換成等待狀態;notify方法是用來通知某個掛起阻塞佇列中的執行緒,讓其中的某個執行緒可以恢復執行,此時執行緒由等待狀態變為執行狀態。

wait、和notify方法為啥和鎖關係這麼密切呢?顯而易見的原因是,執行緒在執行函式的時候,在一個資源得不到的時候,或者說得不到鎖的時候,只有兩種選擇,要不就是死迴圈在那,要不就是掛起等待,等著資源或者說鎖被其他執行緒釋放後通知本執行緒繼續執行!  wait和notify除了用線上程同步問題的解決中,在沒有同步問題的多執行緒程式設計中,wait和notify還可以用來實現普通的等待和通知機制,即單純的改變執行緒執行狀態機來解決某些問題----比如:IO程式設計中的阻塞和非阻塞!

好了,下面來說說鎖!

鎖就相當於對多執行緒共享資源的看門人,其實可以理解為一個原子的狀態變數,可以簡單到只有兩個操作——lock和unlock!lock就是原子的修改鎖變數狀態為上鎖態,unlock就是原子的修改鎖狀態為未上鎖態!

沒有上鎖態被某個執行緒修改為上鎖態後就可以訪問資源,其他的執行緒再去獲取鎖狀態的時候發現鎖被上鎖,只有兩種選擇:死迴圈等待或者阻塞等待被執行,其中死迴圈等待的鎖俗稱自旋鎖,阻塞等待的鎖是普通的阻塞鎖~ 自旋鎖是樂觀鎖(這裡不講)

把鎖上鎖的執行緒在訪問完資源後必須要釋放鎖,即修改鎖狀態為未上鎖狀態,以便讓其他執行緒有機會出來競爭鎖~這裡分兩種情況:自旋鎖直接修改鎖狀態為未上鎖就可以,對於阻塞鎖解鎖的執行緒還要notify通知其他執行緒恢復執行來競爭鎖~

再來說一說死鎖:

所謂死鎖就是一個執行緒想要獲取未上鎖狀態的鎖,但是永遠獲取不到! 其實就是這麼簡單的概念!至於為什麼獲取不到鎖,是因為程式碼的錯誤導致佔有鎖的執行緒永遠不會釋放鎖!

再來說一說可重入鎖:

所謂可衝重入鎖就是在同一個已經獲取鎖的執行緒內,再多次呼叫獲取鎖會不會產生死鎖,會產生死鎖的鎖就是不可重入鎖,不會死鎖的就是可重入的鎖。普通的不可重入鎖,當在一個執行緒內獲取了鎖後,鎖的狀態就變為了上鎖態,然後當前執行緒內再次呼叫獲取鎖,發現鎖是上鎖態,自己就掛起阻塞等待或者自旋等待了,這樣導致的後果是佔用鎖的當前執行緒永遠不會釋放鎖,其他執行緒和自己都無法繼續執行!這樣就導致了死鎖!

如何實現可重入呢?很簡單,只需要一個執行緒在獲取鎖的時候判斷下鎖是不是已經被當前執行緒獲取了,如果是,就忽略鎖的鎖狀態,直接預設獲取鎖,如果鎖不是被當前執行緒獲取的,才阻塞等待或者自旋鎖等待!

(完)