歡迎關注個人公眾號:石杉的架構筆記(ID:shishan100)
週一至週五早8點半!精品技術文章準時送上!
一、寫在前面
上篇文章(大白話聊聊Java併發面試問題之談談你對AQS的理解?)聊了一下java併發包中的AQS的工作原理,也間接說明了ReentrantLock的工作原理。
這篇文章接著來聊一個話題,java併發包中的公平鎖與非公平鎖有啥區別?
二、什麼是非公平鎖?
先來聊聊非公平鎖是啥,現在大家先回過頭來看下面這張圖。
如上圖,現線上程1加了鎖,然後執行緒2嘗試加鎖,失敗後進入了等待佇列,處於阻塞中。然後執行緒1釋放了鎖,準備來喚醒執行緒2重新嘗試加鎖。
注意一點,此時執行緒2可還停留在等待佇列裡啊,還沒開始嘗試重新加鎖呢!
然而,不幸的事情發生了,這時半路殺出個程咬金,來了一個執行緒3!執行緒3突然嘗試對ReentrantLock發起加鎖操作,此時會發生什麼事情?
很簡單!執行緒2還沒來得及重新嘗試加鎖呢。也就是說,還沒來得及嘗試重新執行CAS操作將state的值從0變為1呢!執行緒3衝上來直接一個CAS操作,嘗試將state的值從0變為1,結果還成功了!
一旦CAS操作成功,執行緒3就會將“加鎖執行緒”這個變數設定為他自己。給大家來一張圖,看看這整個過程:
明明人家執行緒2規規矩矩的排隊領鎖呢,結果你執行緒3不守規矩,執行緒1剛釋放鎖,不分青紅皁白,直接就跑過來搶先加鎖了。
這就導致執行緒2被喚醒過後,重新嘗試加鎖執行CAS操作,結果毫無疑問,失敗!
原因很簡單啊!因為加鎖CAS操作,是要嘗試將state從0變為1,結果此時state已經是1了,所以CAS操作一定會失敗!
一旦加鎖失敗,就會導致執行緒2繼續留在等待佇列裡不斷的等著,等著執行緒3釋放鎖之後,再來喚醒自己,真是可憐!先來的執行緒2居然加不到鎖!
同樣給大家來一張圖,體會一下執行緒2這無助的過程:
上述的鎖策略,就是所謂的非公平鎖!
如果你用預設的建構函式來建立ReentrantLock物件,預設的鎖策略就是非公平的。
在非公平鎖策略之下,不一定說先來排隊的執行緒就就先會得到機會加鎖,而是出現各種執行緒隨意搶佔的情況。
那如果要實現公平鎖的策略該怎麼辦呢?也很簡單,在構造ReentrantLock物件的時候傳入一個true即可:
ReentrantLock lock = new ReentrantLock(true)
此時就是說讓他使用公平鎖的策略,那麼公平鎖具體是什麼意思呢?
三、什麼是公平鎖?
我們們重新回到第一張圖,就是執行緒1剛剛釋放鎖之後,執行緒2還沒來得及重新加鎖的那個狀態。
同樣,這時假設來了一個執行緒3,突然殺出來,想要加鎖。
如果是公平鎖的策略,那麼此時執行緒3不會跟個愣頭青一樣盲目的直接加鎖。
他會先判斷一下:咦?AQS的等待佇列裡,有沒有人在排隊啊?如果有人在排隊的話,說明我前面有兄弟正想要加鎖啊!
如果AQS的佇列裡真的有執行緒排著隊,那我執行緒3就不能跟個二愣子一樣直接搶佔加鎖了。
因為現在我們們是公平策略,得按照先來後到的順序依次排隊,誰先入隊,誰就先從佇列裡出來加鎖!
所以,執行緒3此時一判斷,發現佇列裡有人排隊,自己就會乖乖的排到佇列後面去,而不會貿然加鎖!
同樣,整個過程我們用下面這張圖給大家直觀的展示一下:
上面的等待佇列中,執行緒3會按照公平原則直接進入佇列尾部進行排隊。
接著,執行緒2不是被喚醒了麼?他就會重新嘗試進行CAS加鎖,此時沒人跟他搶,他當然可以加鎖成功了。
然後呢,執行緒2就會將state值變為1,同時設定“加鎖執行緒”是自己。最後,執行緒2自己從等待佇列裡出隊。
整個過程,參見下圖:
這個就是公平鎖的策略,過來加鎖的執行緒全部是按照先來後到的順序,依次進入等待佇列中排隊的,不會盲目的胡亂搶佔加鎖,非常的公平。
四、小結
好了,通過畫圖和文字分析,相信大家都明白什麼是公平鎖,什麼是非公平鎖了!
不過要知道java併發包裡很多鎖預設的策略都是非公平的,也就是可能後來的執行緒先加鎖,先來的執行緒後加鎖。
而一般情況下,非公平的策略都沒什麼大問題,但是大家要對這個策略做到心裡有數,在開發的時候,需要自己來考慮和權衡是要用公平策略還是非公平策略。
併發系列文章,正在更新中,歡迎關注:
大白話聊聊Java併發面試問題之volatile到底是什麼?
大白話聊聊Java併發面試問題之Java 8如何優化CAS效能?
大白話聊聊Java併發面試問題之談談你對AQS的理解?
《大白話聊聊Java併發面試問題之公平鎖與非公平鎖是啥?》
《大白話聊聊Java併發面試問題之微服務註冊中心的讀寫鎖優化?》,敬請期待
END
如有收穫,請幫忙轉發,您的鼓勵是作者最大的動力,謝謝!
一大波微服務、分散式、高併發、高可用的原創系列文章正在路上
歡迎掃描下方二維碼,持續關注:
石杉的架構筆記(id:shishan100)
十餘年BAT架構經驗傾囊相授
推薦閱讀:2、【雙11狂歡的背後】微服務註冊中心如何承載大型系統的千萬級訪問?
3、【效能優化之道】每秒上萬併發下的Spring Cloud引數優化實戰
6、大規模叢集下Hadoop NameNode如何承載每秒上千次的高併發訪問
7、【效能優化的祕密】Hadoop如何將TB級大檔案的上傳效能優化上百倍
8、拜託,面試請不要再問我TCC分散式事務的實現原理坑爹呀!
9、【坑爹呀!】最終一致性分散式事務如何保障實際生產中99.99%高可用?
11、【眼前一亮!】看Hadoop底層演算法如何優雅的將大規模叢集效能提升10倍以上?
16、億級流量系統架構之如何設計全鏈路99.99%高可用架構
18、大白話聊聊Java併發面試問題之volatile到底是什麼?