面試官:說一下公平鎖和非公平鎖的區別?

前言

上次我們提到了樂觀鎖和悲觀鎖,那我們知道鎖的類型還有很多種,我們今天簡單聊一下,公平鎖和非公平鎖兩口子,以及他們在我們代碼中的實踐。

正文

開始聊之前,我先大概說一下他們兩者的定義,幫大家回顧或者認識一下。

公平鎖:多個線程按照申請鎖的順序去獲得鎖,線程會直接進入隊列去排隊,永遠都是隊列的第一位才能得到鎖。

  • 優點:所有的線程都能得到資源,不會餓死在隊列中。
  • 缺點:吞吐量會下降很多,隊列裡面除了第一個線程,其他的線程都會阻塞,cpu喚醒阻塞線程的開銷會很大。

非公平鎖:多個線程去獲取鎖的時候,會直接去嘗試獲取,獲取不到,再去進入等待隊列,如果能獲取到,就直接獲取到鎖。

  • 優點:可以減少CPU喚醒線程的開銷,整體的吞吐效率會高點,CPU也不必取喚醒所有線程,會減少喚起線程的數量。
  • 缺點:你們可能也發現了,這樣可能導致隊列中間的線程一直獲取不到鎖或者長時間獲取不到鎖,導致餓死。

我舉個例子給他家通俗易懂的講一下的,想了好幾天終於在前天跟三歪去肯德基買早餐排隊的時候發現了怎麼舉例了。

現在是早餐時間,敖丙想去kfc搞個早餐,發現有很多人了,一過去沒多想,就乖乖到隊尾排隊,這樣大家都覺得很公平,先到先得,所以這是公平鎖咯。

面試官:說一下公平鎖和非公平鎖的區別?

那非公平鎖就是,敖丙過去買早餐,發現大家都在排隊,但是敖丙這個人有點渣的,就是喜歡插隊,那他就直接懟到第一位那去,後面的雞蛋,米豆都不行,我插隊也不敢說什麼,只能默默忍受了。

面試官:說一下公平鎖和非公平鎖的區別?

但是偶爾,雞蛋也會崛起,叫我滾到後面排隊,我也是欺軟怕硬,默默到後面排隊,就插隊失敗了。

面試官:說一下公平鎖和非公平鎖的區別?

介紹完簡單的例子,大家可能會說,渣丙,這個我也知道的啊。

我們是不是應該回歸真正的實現了,其實在大家經常使用的ReentrantLock中就有相關公平鎖,非公平鎖的實現了。

大家還記得我在樂觀鎖、悲觀鎖章節提到的Sync類麼,是ReentrantLock他本身的一個內部類,他繼承了AbstractQueuedSynchronizer,我們在操作鎖的大部分操作,都是Sync本身去實現的。

面試官:說一下公平鎖和非公平鎖的區別?

Sync呢又分別有兩個子類:FairSync和NofairSync

面試官:說一下公平鎖和非公平鎖的區別?

他們子類的名字就可以見名知意了,公平和不公平那又是怎麼在代碼層面體現的呢?

公平鎖:

面試官:說一下公平鎖和非公平鎖的區別?

你可以看到,他加了一個hasQueuedPredecessors的判斷,那他判斷裡面有些什麼玩意呢?

面試官:說一下公平鎖和非公平鎖的區別?

代碼的大概意思也是判斷當前的線程是不是位於同步隊列的首位,是就是返回true,否就返回false。

我總覺得寫到這裡就應該差不多了,但是我坐下來,靜靜的思考之後發現,還是差了點什麼。

上次聊過ReentrantLock了,但是AQS什麼的我都只是提了一嘴,一個線程進來,他整個處理鏈路到底是怎樣的呢?

公平鎖到底公平不公平呢?讓我們一起跟著丙丙走進ReentrantLock的內心世界。

上面提了這麼多,我想你應該是有所瞭解了,那一個線程進來ReentrantLock這個渣男是怎麼不公平的呢?(默認是非公平鎖)

我先畫個圖,幫助大家瞭解下細節:

ReentrantLock的Sync繼承了AbstractQueuedSynchronizer也就是我們常說的AQS

面試官:說一下公平鎖和非公平鎖的區別?

他也是ReentrantLock加鎖釋放鎖的核心,大致的內容我之前一期提到了,我就不過多贅述了,他們看看一次加鎖的過程吧。

A線程準備進去獲取鎖,首先判斷了一下state狀態,發現是0,所以可以CAS成功,並且修改了當前持有鎖的線程為自己。

面試官:說一下公平鎖和非公平鎖的區別?

這個時候B線程也過來了,也是一上來先去判斷了一下state狀態,發現是1,那就CAS失敗了,真晦氣,只能乖乖去等待隊列,等著喚醒了,先去睡一覺吧。

面試官:說一下公平鎖和非公平鎖的區別?

A持有久了,也有點膩了,準備釋放掉鎖,給別的仔一個機會,所以改了state狀態,抹掉了持有鎖線程的痕跡,準備去叫醒B。

面試官:說一下公平鎖和非公平鎖的區別?

這個時候有個帶綠帽子的仔C過來了,發現state怎麼是0啊,果斷CAS修改為1,還修改了當前持有鎖的線程為自己。

B線程被A叫醒準備去獲取鎖,發現state居然是1,CAS就失敗了,只能失落的繼續回去等待隊列,路線還不忘罵A渣男,怎麼騙自己,欺騙我的感情。

面試官:說一下公平鎖和非公平鎖的區別?

諾以上就是一個非公平鎖的線程,這樣的情況就有可能像B這樣的線程長時間無法得到資源,優點就是可能有的線程減少了等待時間,提高了利用率。

現在都是默認非公平了,想要公平就得給構造器傳值true。

ReentrantLock lock = new ReentrantLock(true);

面試官:說一下公平鎖和非公平鎖的區別?

說完非公平,那我也說一下公平的過程吧:

線A現在想要獲得鎖,先去判斷下state,發現也是0,去看了看隊列,自己居然是第一位,果斷修改了持有線程為自己。

面試官:說一下公平鎖和非公平鎖的區別?

線程b過來了,去判斷一下state,嗯哼?居然是state=1,那cas就失敗了呀,所以只能乖乖去排隊了。

面試官:說一下公平鎖和非公平鎖的區別?

未命名文件 (https://tva1.sinaimg.cn/large/00831rSTly1gcxaojuen2j30oa0jxgmh.jpg)

線程A暖男來了,持有沒多久就釋放了,改掉了所有的狀態就去喚醒線程B了,這個時候線程C進來了,但是他先判斷了下state發現是0,以為有戲,然後去看了看隊列,發現前面有人了,作為新時代的良好市民,果斷排隊去了。

面試官:說一下公平鎖和非公平鎖的區別?

線程B得到A的召喚,去判斷state了,發現值為0,自己也是隊列的第一位,那很香呀,可以得到了。

面試官:說一下公平鎖和非公平鎖的區別?

總結:

總結我不說話了,但是去獲取鎖判斷的源碼,箭頭所指的位置,現在是不是都被我合理的解釋了,當前線程,state,是否是0,是否是當前線程等等,都去思考下。

面試官:說一下公平鎖和非公平鎖的區別?

鬼知道我為了畫圖,畫了多少費稿,點個贊過分麼?

面試官:說一下公平鎖和非公平鎖的區別?

課後作業

公平鎖真的公平麼?那什麼層面不是絕對的公平,什麼層面才能算公平?

我是敖丙,一個在互聯網苟且偷生的工具人。

最好的關係是互相成就

,各位的「三連」就是丙丙創作的最大動力,我們下期見!


分享到:


相關文章: