大白話聊聊Java併發面試問題之公平鎖與非公平鎖是啥?【石杉的架構筆記】

石杉的架構筆記發表於2018-12-07

歡迎關注個人公眾號:石杉的架構筆記(ID:shishan100)

週一至週五早8點半!精品技術文章準時送上!

一、寫在前面

上篇文章(大白話聊聊Java併發面試問題之談談你對AQS的理解?)聊了一下java併發包中的AQS的工作原理,也間接說明了ReentrantLock的工作原理。

這篇文章接著來聊一個話題,java併發包中的公平鎖與非公平鎖有啥區別?


二、什麼是非公平鎖?

先來聊聊非公平鎖是啥,現在大家先回過頭來看下面這張圖。

大白話聊聊Java併發面試問題之公平鎖與非公平鎖是啥?【石杉的架構筆記】

如上圖,現線上程1加了鎖,然後執行緒2嘗試加鎖,失敗後進入了等待佇列,處於阻塞中。然後執行緒1釋放了鎖,準備來喚醒執行緒2重新嘗試加鎖。

注意一點,此時執行緒2可還停留在等待佇列裡啊,還沒開始嘗試重新加鎖呢!

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

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

一旦CAS操作成功,執行緒3就會將“加鎖執行緒”這個變數設定為他自己。給大家來一張圖,看看這整個過程:

大白話聊聊Java併發面試問題之公平鎖與非公平鎖是啥?【石杉的架構筆記】


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

這就導致執行緒2被喚醒過後,重新嘗試加鎖執行CAS操作,結果毫無疑問,失敗!

原因很簡單啊!因為加鎖CAS操作,是要嘗試將state從0變為1,結果此時state已經是1了,所以CAS操作一定會失敗!

一旦加鎖失敗,就會導致執行緒2繼續留在等待佇列裡不斷的等著,等著執行緒3釋放鎖之後,再來喚醒自己,真是可憐!先來的執行緒2居然加不到鎖!

同樣給大家來一張圖,體會一下執行緒2這無助的過程:

大白話聊聊Java併發面試問題之公平鎖與非公平鎖是啥?【石杉的架構筆記】


上述的鎖策略,就是所謂的非公平鎖

如果你用預設的建構函式來建立ReentrantLock物件,預設的鎖策略就是非公平的。

在非公平鎖策略之下,不一定說先來排隊的執行緒就就先會得到機會加鎖,而是出現各種執行緒隨意搶佔的情況。

那如果要實現公平鎖的策略該怎麼辦呢?也很簡單,在構造ReentrantLock物件的時候傳入一個true即可:

ReentrantLock lock = new ReentrantLock(true)

此時就是說讓他使用公平鎖的策略,那麼公平鎖具體是什麼意思呢?


三、什麼是公平鎖?

我們們重新回到第一張圖,就是執行緒1剛剛釋放鎖之後,執行緒2還沒來得及重新加鎖的那個狀態。

大白話聊聊Java併發面試問題之公平鎖與非公平鎖是啥?【石杉的架構筆記】


同樣,這時假設來了一個執行緒3,突然殺出來,想要加鎖。

如果是公平鎖的策略,那麼此時執行緒3不會跟個愣頭青一樣盲目的直接加鎖。

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

如果AQS的佇列裡真的有執行緒排著隊,那我執行緒3就不能跟個二愣子一樣直接搶佔加鎖了。

因為現在我們們是公平策略,得按照先來後到的順序依次排隊,誰先入隊,誰就先從佇列裡出來加鎖!

所以,執行緒3此時一判斷,發現佇列裡有人排隊,自己就會乖乖的排到佇列後面去,而不會貿然加鎖!

同樣,整個過程我們用下面這張圖給大家直觀的展示一下:

大白話聊聊Java併發面試問題之公平鎖與非公平鎖是啥?【石杉的架構筆記】


上面的等待佇列中,執行緒3會按照公平原則直接進入佇列尾部進行排隊。

接著,執行緒2不是被喚醒了麼?他就會重新嘗試進行CAS加鎖,此時沒人跟他搶,他當然可以加鎖成功了。

然後呢,執行緒2就會將state值變為1,同時設定“加鎖執行緒”是自己。最後,執行緒2自己從等待佇列裡出隊。

整個過程,參見下圖:

大白話聊聊Java併發面試問題之公平鎖與非公平鎖是啥?【石杉的架構筆記】


這個就是公平鎖的策略,過來加鎖的執行緒全部是按照先來後到的順序,依次進入等待佇列中排隊的,不會盲目的胡亂搶佔加鎖,非常的公平。


四、小結

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

不過要知道java併發包裡很多鎖預設的策略都是非公平的,也就是可能後來的執行緒先加鎖,先來的執行緒後加鎖。

而一般情況下,非公平的策略都沒什麼大問題,但是大家要對這個策略做到心裡有數,在開發的時候,需要自己來考慮和權衡是要用公平策略還是非公平策略。


併發系列文章,正在更新中,歡迎關注:
大白話聊聊Java併發面試問題之volatile到底是什麼?
大白話聊聊Java併發面試問題之Java 8如何優化CAS效能?
大白話聊聊Java併發面試問題之談談你對AQS的理解?
《大白話聊聊Java併發面試問題之公平鎖與非公平鎖是啥?》
《大白話聊聊Java併發面試問題之微服務註冊中心的讀寫鎖優化?》敬請期待


END


如有收穫,請幫忙轉發,您的鼓勵是作者最大的動力,謝謝!


一大波微服務、分散式、高併發、高可用的原創系列文章正在路上

歡迎掃描下方二維碼,持續關注:

大白話聊聊Java併發面試問題之公平鎖與非公平鎖是啥?【石杉的架構筆記】

石杉的架構筆記(id:shishan100)

十餘年BAT架構經驗傾囊相授


推薦閱讀:

1、拜託!面試請不要再問我Spring Cloud底層原理

2、【雙11狂歡的背後】微服務註冊中心如何承載大型系統的千萬級訪問?

3、【效能優化之道】每秒上萬併發下的Spring Cloud引數優化實戰

4、微服務架構如何保障雙11狂歡下的99.99%高可用

5、兄弟,用大白話告訴你小白都能聽懂的Hadoop架構原理

6、大規模叢集下Hadoop NameNode如何承載每秒上千次的高併發訪問

7、【效能優化的祕密】Hadoop如何將TB級大檔案的上傳效能優化上百倍

8、拜託,面試請不要再問我TCC分散式事務的實現原理坑爹呀!

9、【坑爹呀!】最終一致性分散式事務如何保障實際生產中99.99%高可用?

10、拜託,面試請不要再問我Redis分散式鎖的實現原理!

11、【眼前一亮!】看Hadoop底層演算法如何優雅的將大規模叢集效能提升10倍以上?

12、億級流量系統架構之如何支撐百億級資料的儲存與計算

13、億級流量系統架構之如何設計高容錯分散式計算系統

14、億級流量系統架構之如何設計承載百億流量的高效能架構

15、億級流量系統架構之如何設計每秒十萬查詢的高併發架構

16、億級流量系統架構之如何設計全鏈路99.99%高可用架構

17、七張圖徹底講清楚ZooKeeper分散式鎖的實現原理

18、大白話聊聊Java併發面試問題之volatile到底是什麼?

19、大白話聊聊Java併發面試問題之Java 8如何優化CAS效能?

20、大白話聊聊Java併發面試問題之談談你對AQS的理解?





相關文章