1. 程式人生 > >面試官:你說說ReentrantLock和Synchronized區別

面試官:你說說ReentrantLock和Synchronized區別

大家好!又和大家見面了。為了避免面試尷尬,今天同比較通俗語言和大家聊下ReentrantLock和Synchronized區別!

 

使用方式


Synchronized可以修飾例項方法,靜態方法,程式碼塊。自動釋放鎖。

ReentrantLock一般需要try catch finally語句,在try中獲取鎖,在finally釋放鎖。需要手動釋放鎖。

 

實現方式


Synchronized是重量級鎖。重量級鎖需要將執行緒從核心態和使用者態來回切換。如:A執行緒切換到B執行緒,A執行緒需要儲存當前現場,B執行緒切換也需要儲存現場。這樣做的缺點是耗費系統資源。

ReentrantLock是輕量級鎖。採用cas+volatile管理執行緒,不需要執行緒切換切換,獲取鎖執行緒覺得自己肯定能成功,這是一種樂觀的思想(可能失敗)。

用一個形象例子來說明:比如您在看我這篇文章時,覺得“重量級鎖”概念不是很明白,就立刻去翻看關於“重量級鎖”的其他文章,過會兒回頭再繼續往下面看, 這種行為我們稱為切換。儲存現場的意思就是你大腦需要記住你跳躍的點然後繼續閱讀,如果文章篇幅大,你的大腦可能需要記憶越多的東西,會越耗費腦神經。同理,在輕量級鎖中,你覺得“重量級鎖”概念不是很明白,他不會立刻去翻看其他文章,他會堅持會兒繼續看,如果實在不明白再去翻資料了。需要注意的是:這是兩種不一樣的思維方式,前者是被動阻塞悲觀鎖,狀態是block,後者是主動的阻塞樂觀鎖,狀態是wait。

 

公平和非公平


Synchronized只有非公平鎖。

ReentrantLock提供公平和非公平兩種鎖,預設是非公平的。公平鎖通過建構函式傳遞true表示。

用一個形象例子來說明:排隊打飯,Synchronized允許插隊,如果ReentrantLock是公平鎖,就不許插隊了。

 

可重入鎖


Synchronized和ReentrantLock都是可重入的,Synchronized是本地方法是C++實現,而ReentrantLock是JUC包用Java實現。

用一個形象例子來說明:如下圖:一個房中房,房裡外各有一把鎖,但只有唯一的鑰匙可以開,擁有鑰匙的人可以先進入門1,再進入門2,其中進入門2就是叫鎖可重入了。

在ReentrantLock中,重入次數用整形state表示。進入1次遞增1次,出來1次遞減1次。

 

 

可中斷的


Synchronized是不可中斷的。

ReentrantLock提供可中斷和不可中斷兩種方式。其中lockInterruptibly方法表示可中斷,lock方法表示不可中斷。

用一個形象例子來說明:叫練和叫練女朋友一起去做核酸,叫練女朋友排在前面,所以叫練女朋友進門先做,叫練在門外排隊等待過程中突然接到領導電話要回去修改bug,叫練現在有兩種選擇,1.不和女朋友打招呼,立即回去修改bug,2.等待女朋友做完核酸,進去和女朋友打個招呼,然後回去修改bug。這兩種情況最終都會導致一個結果,叫練無法完成核酸,在這兩種情況中,雖然叫練都被領導中斷了,但第一種情況叫練立即反饋領導叫可中斷,第二種情況是叫練為了不做單身狗,打個招呼再去修改bug,需要注意的是“打招呼”需要提前獲取鎖,也就是需要等待叫練女朋友做完核酸檢測。如果是你,遇到叫練這種情況,你會怎麼辦?期待你的答覆!點關注,不迷路,我是叫練【公眾號】,邊叫邊練。

 

條件佇列


Synchronized只有一個等待佇列。

ReentrantLock中一把鎖可以對應多個條件佇列。通過newCondition表示。

用一個形象例子來說明:母雞下蛋和撿蛋人對應生產者和消費者,母雞產蛋後,撿蛋人需要被母雞通知,母雞產蛋過程中,其中撿蛋人就會入條件佇列(等待佇列)。撿蛋人撿蛋完成後,撿蛋人需要通知母雞繼續產蛋,撿蛋人撿蛋過程中,母雞也需要加入條件佇列等待。

 

 

注意:有幾個概念需要說明下。同步佇列,條件佇列和等待佇列。

同步佇列:多執行緒同時競爭一把鎖失敗被掛起的執行緒。

條件佇列:正在執行的執行緒呼叫await/wait,從同步佇列加入的執行緒會進入條件佇列。正在執行執行緒呼叫signal/signalAll/notify/notifyAll,會將條件佇列一個執行緒或多個執行緒加入到同步佇列。

等待佇列:和條件佇列一個概念。

 

 

總結


今天我們用通俗易懂的文字描述了ReentrantLock和Synchronized關係。喜歡的請點贊加評論哦!點關注,不迷路,我是叫練【公眾號】,邊叫邊練。期待我們下次再見!