顯示鎖與隱式鎖的區(qū)別

????????在面試的過程中有可能會問到:在Java并發(fā)編程中,鎖有兩種實現(xiàn):使用隱式鎖和使用顯示鎖分別是什么?兩者的區(qū)別是什么?所謂的顯式鎖和隱式鎖的區(qū)別也就是說說Synchronized和lock(下文就用ReentrantLock來代之lock)的區(qū)別。

本文主要內(nèi)容:將通過七個方面詳細介紹sync和lock的區(qū)別。通過生活case中的X二代和普通人比較大家更容易理解這兩者之間的區(qū)別

Java中隱式鎖:synchronized;顯式鎖:lock

sync和lock的區(qū)別

一:出身不同

從synchronized和lock的出身(原始的構(gòu)成)來看看兩者的不同。

synchronized:Java中的關(guān)鍵字,是由JVM來維護的。是JVM層面的鎖。

Lock:是JDK5以后才出現(xiàn)的具體的類。使用lock是調(diào)用對應的API。是API層面的鎖。

synchronized是底層是通過monitorenter進行加鎖(底層是通過monitor對象來完成的,其中的wait/notify等方法也是依賴于monitor對象的。只有在同步塊或者是同步方法中才可以調(diào)用wait/notify等方法的。因為只有在同步塊或者是同步方法中,JVM才會調(diào)用monitory對象的);通過monitorexit來退出鎖的。

而lock是通過調(diào)用對應的API方法來獲取鎖和釋放鎖的。

一句話概述:可以把synchronized理解為官二代或者是星二代。從娘胎出來自帶光環(huán)的。Lock就是我們普通努力上進的人。

二:使用方式不同

synchronized是隱式鎖。Lock是顯示鎖

所謂的顯示和隱式就是在使用的時候,使用者要不要手動寫代碼去獲取鎖和釋放鎖的操作。

我們大家都知道,在使用synchronized關(guān)鍵字的時候,我們使用者根本不用寫其他的代碼,然后程序就能夠獲取鎖和釋放鎖了。那是因為當synchronized代碼塊執(zhí)行完成之后,系統(tǒng)會自動的讓程序釋放占用的鎖。synchronized是由系統(tǒng)維護的,如果非邏輯問題的話話,是不會出現(xiàn)死鎖的。

在使用lock的時候,我們使用者需要手動的獲取和釋放鎖。如果沒有釋放鎖,就有可能導致出現(xiàn)死鎖的現(xiàn)象。手動獲取鎖方法:lock.lock()。釋放鎖:unlock方法。需要配合tyr/finaly語句塊來完成。

兩者用法對比如下:

用生活中的一個case來形容這個不同:官二代和普通人的你在進入機關(guān)大院的時候待遇。官二代不需要出示什么證件就可以進入,但是你需要手動出示證件才可以進入。

三:等待是否可中斷

synchronized是不可中斷的。除非拋出異?;蛘哒_\行完成

Lock可以中斷的。中斷方式:

1:調(diào)用設(shè)置超時方法tryLock(long timeout ,timeUnit unit)

2:調(diào)用lockInterruptibly()放到代碼塊中,然后調(diào)用interrupt()方法可以中斷

生活中小case來理解這一區(qū)別:官二代一般不會做飯。都會去餐廳點餐等待著餐廳出餐。普通人的你既可以去餐廳等待,如果等待時間長的話,你就可以回去自己做飯了。

四:加鎖的時候是否可以公平

synchronized;非公平鎖

lock:兩者都可以的。默認是非公平鎖。在其構(gòu)造方法的時候可以傳入Boolean值。

true:公平鎖

false:非公平鎖

生活中小case來理解這個區(qū)別:官二代一般都不排隊,喜歡插隊的。普通人的你雖然也喜歡插隊。但是如果遇到讓排隊的情況下,你還是會排隊的。

五:鎖綁定多個條件來condition

synchronized:沒有。要么隨機喚醒一個線程;要么是喚醒所有等待的線程。

Lock:用來實現(xiàn)分組喚醒需要喚醒的線程,可以精確的喚醒,而不是像sync那樣,不能精確喚醒線程。

六:從性能比較

synchronized是托管給JVM執(zhí)行的,而Lock是java寫的控制鎖的代碼。在java1.5中,synchronized是低效能的。因為這是一個重量級操作,需要調(diào)用操作接口,導致有可能加鎖消耗的系統(tǒng)空間比加鎖以外的操作更多。相比之下使用Java提供的Lock對象,性能更高一些。但在java1.6之后,發(fā)生了變化。synchronized在語義上很清晰,可以進行很多優(yōu)化,有適自旋,鎖消除,鎖粗化,輕量級鎖,偏向鎖等。導致在Java1.6上synchronized的性能并不比Lock差。官方也表示,他們也支持synchronized,在未來版本中還有優(yōu)化余地。

生活小case理解:在我們一般的認知中,官二代一般都是比較坑爹的吧。但是這幾年也有很多官二代或者是富二代改變了態(tài)度,端正自己態(tài)度,靠自己能力而不是拼爹了。

七:從使用鎖的方式比較

說到這里,還是想提一下著兩種機制的具體區(qū)別。據(jù)我所知,synchronized原始采用的是CPU悲觀鎖機制,即線程獲得的是獨占鎖。獨占鎖以為著其他線程只能依靠阻塞來等待線程釋放鎖。而在CPU抓換線程阻塞時會引起線程上下文切換,黨有很多線程競爭鎖的時候,會引起CPU頻繁的上下文切換導致效率很低。

而Lock用的是樂觀鎖方式。所謂樂觀鎖就是,每次不加鎖而是假設(shè)沒有沖突而去完成某項操作,如果因為沖突失敗就重試,直到成功為止。樂觀鎖實現(xiàn)的機制就是CAS操作(Compare and Swap)。我們可以進一步研究ReentrantLock的源代碼,會發(fā)現(xiàn)其中比較重要的獲得鎖的一個方法是compareAndSetState。這里其實就是調(diào)用CPU提供的特殊指令。

現(xiàn)在的CPU提供了指令,可以自動更改共享數(shù)據(jù),而且能夠檢測到其他線程的干擾,而compareAndSet()就是用這些代替了鎖定。這個算法成為非阻塞算法,意思是一個線程的失敗或者掛起不應該影響其他線程的失敗或掛起的算法。

我也只是了解到這一步,具體到CPU的算法,如果感興趣的讀者可以進一步進行查閱。若有更好的解釋,可以給我留言,我也能更好的學習一下。

?


轉(zhuǎn)載自:

Java并發(fā)之顯式鎖和隱式鎖的區(qū)別 - kaizi1992 - 博客園

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容