聊聊Java併發面試問題之公平鎖與非公平鎖是啥?

一.什麼是非公平鎖?

先來聊聊非公平鎖是啥,如今你們先回過頭來看下面這張圖。image.png 如上圖,如今線程1加了鎖,而後線程2嘗試加鎖,失敗後進入了等待隊列,處於阻塞中。而後線程1釋放了鎖,準備來喚醒線程2從新嘗試加鎖。java

注意一點,此時線程2可還停留在等待隊列裏啊,還沒開始嘗試從新加鎖呢!程序員

然而,不幸的事情發生了,這時半路殺出個程咬金,來了一個線程3!線程3忽然嘗試對ReentrantLock發起加鎖操做,此時會發生什麼事情?面試

很簡單!線程2還沒來得及從新嘗試加鎖呢。也就是說,還沒來得及嘗試從新執行CAS操做將state的值從0變爲1呢!線程3衝上來直接一個CAS操做,嘗試將state的值從0變爲1,結果還成功了!架構

一旦CAS操做成功,線程3就會將「加鎖線程」這個變量設置爲他本身。給你們來一張圖,看看這整個過程:image.png併發

明明人家線程2規規矩矩的排隊領鎖呢,結果你線程3不守規矩,線程1剛釋放鎖,不分青紅皁白,直接就跑過來搶先加鎖了。分佈式

這就致使線程2被喚醒事後,從新嘗試加鎖執行CAS操做,結果毫無疑問,失敗!函數

緣由很簡單啊!由於加鎖CAS操做,是要嘗試將state從0變爲1,結果此時state已是1了,因此CAS操做必定會失敗!高併發

一旦加鎖失敗,就會致使線程2繼續留在等待隊列裏不斷的等着,等着線程3釋放鎖以後,再來喚醒本身,真是可憐!先來的線程2竟然加不到鎖!學習

一樣給你們來一張圖,體會一下線程2這無助的過程:image.png 上述的鎖策略,就是所謂的非公平鎖! 若是你用默認的構造函數來建立ReentrantLock對象,默認的鎖策略就是非公平的。線程

在非公平鎖策略之下,不必定說先來排隊的線程就就先會獲得機會加鎖,而是出現各類線程隨意搶佔的狀況。

**那若是要實現公平鎖的策略該怎麼辦呢?**也很簡單,在構造ReentrantLock對象的時候傳入一個true便可: ReentrantLock lock = new ReentrantLock(true) 此時就是說讓他使用公平鎖的策略,那麼公平鎖具體是什麼意思呢?

二.什麼是公平鎖?

我們從新回到第一張圖,就是線程1剛剛釋放鎖以後,線程2還沒來得及從新加鎖的那個狀態。image.png 一樣,這時假設來了一個線程3,忽然殺出來,想要加鎖。

若是是公平鎖的策略,那麼此時線程3不會跟個愣頭青同樣盲目的直接加鎖。

他會先判斷一下:咦?AQS的等待隊列裏,有沒有人在排隊啊?若是有人在排隊的話,說明我前面有兄弟正想要加鎖啊!

若是AQS的隊列裏真的有線程排着隊,那我線程3就不能跟個二愣子同樣直接搶佔加鎖了。

由於如今我們是公平策略,得按照先來後到的順序依次排隊,誰先入隊,誰就先從隊列裏出來加鎖!

因此,線程3此時一判斷,發現隊列裏有人排隊,本身就會乖乖的排到隊列後面去,而不會貿然加鎖!

一樣,整個過程咱們用下面這張圖給你們直觀的展現一下:image.png 上面的等待隊列中,線程3會按照公平原則直接進入隊列尾部進行排隊。

接着,線程2不是被喚醒了麼?他就會從新嘗試進行CAS加鎖,此時沒人跟他搶,他固然能夠加鎖成功了。

而後呢,線程2就會將state值變爲1,同時設置「加鎖線程」是本身。最後,線程2本身從等待隊列裏出隊。

整個過程,參見下圖:image.png

這個就是公平鎖的策略,過來加鎖的線程所有是按照先來後到的順序,依次進入等待隊列中排隊的,不會盲目的胡亂搶佔加鎖,很是的公平。

三.小結

好了,經過畫圖和文字分析,相信你們都明白什麼是公平鎖,什麼是非公平鎖了!

不過要知道java併發包裏不少鎖默認的策略都是非公平的,也就是可能後來的線程先加鎖,先來的線程後加鎖。

而通常狀況下,非公平的策略都沒什麼大問題,可是你們要對這個策略作到內心有數,在開發的時候,須要本身來考慮和權衡是要用公平策略仍是非公平策略。

讀者福利

針對於上面的面試題我總結出了互聯網公司java程序員面試涉及到的絕大部分面試題及答案作成了文檔和架構視頻資料免費分享給你們(包括Dubbo、Redis、Netty、zookeeper、Spring cloud、分佈式、高併發等架構技術資料),但願能幫助到您面試前的複習且找到一個好的工做,也節省你們在網上搜索資料的時間來學習。

資料獲取方式:加qun羣:749151405 找管理小姐姐免費獲取!

合理利用本身每一分每一秒的時間來學習提高本身,不要再用"沒有時間「來掩飾本身思想上的懶惰!趁年輕,使勁拼,給將來的本身一個交代!

相關文章
相關標籤/搜索