????????在面試的過程中有可能會問到:在Java并發(fā)編程中惶洲,鎖有兩種實(shí)現(xiàn):使用隱式鎖和使用顯示鎖分別是什么骗炉?兩者的區(qū)別是什么?所謂的顯式鎖和隱式鎖的區(qū)別也就是說說Synchronized和lock(下文就用ReentrantLock來代之lock)的區(qū)別。
本文主要內(nèi)容:將通過七個方面詳細(xì)介紹sync和lock的區(qū)別归园。通過生活case中的X二代和普通人比較大家更容易理解這兩者之間的區(qū)別
Java中隱式鎖:synchronized枯跑;顯式鎖:lock
sync和lock的區(qū)別
一:出身不同
從synchronized和lock的出身(原始的構(gòu)成)來看看兩者的不同惨驶。
synchronized:Java中的關(guān)鍵字,是由JVM來維護(hù)的敛助。是JVM層面的鎖粗卜。
Lock:是JDK5以后才出現(xiàn)的具體的類。使用lock是調(diào)用對應(yīng)的API纳击。是API層面的鎖续扔。
synchronized是底層是通過monitorenter進(jìn)行加鎖(底層是通過monitor對象來完成的,其中的wait/notify等方法也是依賴于monitor對象的焕数。只有在同步塊或者是同步方法中才可以調(diào)用wait/notify等方法的纱昧。因?yàn)橹挥性谕綁K或者是同步方法中,JVM才會調(diào)用monitory對象的)堡赔;通過monitorexit來退出鎖的识脆。
而lock是通過調(diào)用對應(yīng)的API方法來獲取鎖和釋放鎖的。
一句話概述:可以把synchronized理解為官二代或者是星二代善已。從娘胎出來自帶光環(huán)的灼捂。Lock就是我們普通努力上進(jìn)的人。
二:使用方式不同
synchronized是隱式鎖换团。Lock是顯示鎖
所謂的顯示和隱式就是在使用的時候悉稠,使用者要不要手動寫代碼去獲取鎖和釋放鎖的操作。
我們大家都知道艘包,在使用synchronized關(guān)鍵字的時候的猛,我們使用者根本不用寫其他的代碼洒扎,然后程序就能夠獲取鎖和釋放鎖了。那是因?yàn)楫?dāng)synchronized代碼塊執(zhí)行完成之后衰絮,系統(tǒng)會自動的讓程序釋放占用的鎖袍冷。synchronized是由系統(tǒng)維護(hù)的,如果非邏輯問題的話話猫牡,是不會出現(xiàn)死鎖的胡诗。
在使用lock的時候,我們使用者需要手動的獲取和釋放鎖淌友。如果沒有釋放鎖煌恢,就有可能導(dǎo)致出現(xiàn)死鎖的現(xiàn)象。手動獲取鎖方法:lock.lock()震庭。釋放鎖:unlock方法瑰抵。需要配合tyr/finaly語句塊來完成。
兩者用法對比如下:
用生活中的一個case來形容這個不同:官二代和普通人的你在進(jìn)入機(jī)關(guān)大院的時候待遇器联。官二代不需要出示什么證件就可以進(jìn)入二汛,但是你需要手動出示證件才可以進(jìn)入。
三:等待是否可中斷
synchronized是不可中斷的拨拓。除非拋出異畴燃眨或者正常運(yùn)行完成
Lock可以中斷的。中斷方式:
1:調(diào)用設(shè)置超時方法tryLock(long timeout ,timeUnit unit)
2:調(diào)用lockInterruptibly()放到代碼塊中渣磷,然后調(diào)用interrupt()方法可以中斷
生活中小case來理解這一區(qū)別:官二代一般不會做飯婿着。都會去餐廳點(diǎn)餐等待著餐廳出餐。普通人的你既可以去餐廳等待醋界,如果等待時間長的話竟宋,你就可以回去自己做飯了。
四:加鎖的時候是否可以公平
synchronized;非公平鎖
lock:兩者都可以的形纺。默認(rèn)是非公平鎖丘侠。在其構(gòu)造方法的時候可以傳入Boolean值。
true:公平鎖
false:非公平鎖
生活中小case來理解這個區(qū)別:官二代一般都不排隊(duì)挡篓,喜歡插隊(duì)的婉陷。普通人的你雖然也喜歡插隊(duì)。但是如果遇到讓排隊(duì)的情況下官研,你還是會排隊(duì)的秽澳。
五:鎖綁定多個條件來condition
synchronized:沒有。要么隨機(jī)喚醒一個線程戏羽;要么是喚醒所有等待的線程担神。
Lock:用來實(shí)現(xiàn)分組喚醒需要喚醒的線程,可以精確的喚醒始花,而不是像sync那樣妄讯,不能精確喚醒線程孩锡。
六:從性能比較
synchronized是托管給JVM執(zhí)行的,而Lock是java寫的控制鎖的代碼亥贸。在java1.5中躬窜,synchronized是低效能的。因?yàn)檫@是一個重量級操作炕置,需要調(diào)用操作接口荣挨,導(dǎo)致有可能加鎖消耗的系統(tǒng)空間比加鎖以外的操作更多。相比之下使用Java提供的Lock對象朴摊,性能更高一些默垄。但在java1.6之后,發(fā)生了變化甚纲。synchronized在語義上很清晰口锭,可以進(jìn)行很多優(yōu)化,有適自旋介杆,鎖消除鹃操,鎖粗化,輕量級鎖这溅,偏向鎖等组民。導(dǎo)致在Java1.6上synchronized的性能并不比Lock差棒仍。官方也表示悲靴,他們也支持synchronized,在未來版本中還有優(yōu)化余地莫其。
生活小case理解:在我們一般的認(rèn)知中癞尚,官二代一般都是比較坑爹的吧。但是這幾年也有很多官二代或者是富二代改變了態(tài)度乱陡,端正自己態(tài)度浇揩,靠自己能力而不是拼爹了。
七:從使用鎖的方式比較
說到這里憨颠,還是想提一下著兩種機(jī)制的具體區(qū)別胳徽。據(jù)我所知,synchronized原始采用的是CPU悲觀鎖機(jī)制爽彤,即線程獲得的是獨(dú)占鎖养盗。獨(dú)占鎖以為著其他線程只能依靠阻塞來等待線程釋放鎖。而在CPU抓換線程阻塞時會引起線程上下文切換适篙,黨有很多線程競爭鎖的時候往核,會引起CPU頻繁的上下文切換導(dǎo)致效率很低。
而Lock用的是樂觀鎖方式嚷节。所謂樂觀鎖就是聂儒,每次不加鎖而是假設(shè)沒有沖突而去完成某項(xiàng)操作虎锚,如果因?yàn)闆_突失敗就重試,直到成功為止衩婚。樂觀鎖實(shí)現(xiàn)的機(jī)制就是CAS操作(Compare and Swap)窜护。我們可以進(jìn)一步研究ReentrantLock的源代碼,會發(fā)現(xiàn)其中比較重要的獲得鎖的一個方法是compareAndSetState非春。這里其實(shí)就是調(diào)用CPU提供的特殊指令柄慰。
現(xiàn)在的CPU提供了指令,可以自動更改共享數(shù)據(jù)税娜,而且能夠檢測到其他線程的干擾坐搔,而compareAndSet()就是用這些代替了鎖定。這個算法成為非阻塞算法敬矩,意思是一個線程的失敗或者掛起不應(yīng)該影響其他線程的失敗或掛起的算法概行。
我也只是了解到這一步,具體到CPU的算法弧岳,如果感興趣的讀者可以進(jìn)一步進(jìn)行查閱凳忙。若有更好的解釋,可以給我留言禽炬,我也能更好的學(xué)習(xí)一下涧卵。
?
轉(zhuǎn)載自: