------------------------------版本一---------------------------------
1.區(qū)別:
1)Lock是一個(gè)接口,而synchronized是Java中的關(guān)鍵字,synchronized是內(nèi)置的語言實(shí)現(xiàn);
2)synchronized在發(fā)生異常時(shí),會(huì)自動(dòng)釋放線程占有的鎖,因此不會(huì)導(dǎo)致死鎖現(xiàn)象發(fā)生;而Lock在發(fā)生異常時(shí),如果沒有主動(dòng)通過unLock()去釋放鎖,則很可能造成死鎖現(xiàn)象,因此使用Lock時(shí)需要在finally塊中釋放鎖;
3)Lock可以讓等待鎖的線程響應(yīng)中斷,而synchronized卻不行,使用synchronized時(shí),等待的線程會(huì)一直等待下去,不能夠響應(yīng)中斷;
4)通過Lock可以知道有沒有成功獲取鎖,而synchronized卻無法辦到。
5)Lock可以提高多個(gè)線程進(jìn)行讀操作的效率。
總結(jié):ReentrantLock相比synchronized,增加了一些高級(jí)的功能。但也有一定缺陷。
在ReentrantLock類中定義了很多方法,比如:
isFair()//判斷鎖是否是公平鎖
isLocked()//判斷鎖是否被任何線程獲取了
isHeldByCurrentThread()//判斷鎖是否被當(dāng)前線程獲取了
hasQueuedThreads()//判斷是否有線程在等待該鎖
2.兩者在鎖的相關(guān)概念上區(qū)別:
1)可中斷鎖
顧名思義,就是可以相應(yīng)中斷的鎖。
在Java中,synchronized就不是可中斷鎖,而Lock是可中斷鎖。如果某一線程A正在執(zhí)行鎖中的代碼,另一線程B正在等待獲取該鎖,可能由于等待時(shí)間過長(zhǎng),線程B不想等待了,想先處理其他事情,我們可以讓它中斷自己或者在別的線程中中斷它,這種就是可中斷鎖。
lockInterruptibly()的用法體現(xiàn)了Lock的可中斷性。
2)公平鎖
公平鎖即盡量以請(qǐng)求鎖的順序來獲取鎖。比如同是有多個(gè)線程在等待一個(gè)鎖,當(dāng)這個(gè)鎖被釋放時(shí),等待時(shí)間最久的線程(最先請(qǐng)求的線程)會(huì)獲得該鎖(并不是絕對(duì)的,大體上是這種順序),這種就是公平鎖。
非公平鎖即無法保證鎖的獲取是按照請(qǐng)求鎖的順序進(jìn)行的。這樣就可能導(dǎo)致某個(gè)或者一些線程永遠(yuǎn)獲取不到鎖。
在Java中,synchronized就是非公平鎖,它無法保證等待的線程獲取鎖的順序。ReentrantLock可以設(shè)置成公平鎖。
3)讀寫鎖
讀寫鎖將對(duì)一個(gè)資源(比如文件)的訪問分成了2個(gè)鎖,一個(gè)讀鎖和一個(gè)寫鎖。
正因?yàn)橛辛俗x寫鎖,才使得多個(gè)線程之間的讀操作可以并發(fā)進(jìn)行,不需要同步,而寫操作需要同步進(jìn)行,提高了效率。
ReadWriteLock就是讀寫鎖,它是一個(gè)接口,ReentrantReadWriteLock實(shí)現(xiàn)了這個(gè)接口。
可以通過readLock()獲取讀鎖,通過writeLock()獲取寫鎖。
4)綁定多個(gè)條件
一個(gè)ReentrantLock對(duì)象可以同時(shí)綁定多個(gè)Condition對(duì)象,而在synchronized中,鎖對(duì)象的wait()和notify()或notifyAll()方法可以實(shí)現(xiàn)一個(gè)隱含的條件,如果要和多余一個(gè)條件關(guān)聯(lián)的時(shí)候,就不得不額外地添加一個(gè)鎖,而ReentrantLock則無須這么做,只需要多次調(diào)用new Condition()方法即可。
3.性能比較
在性能上來說,如果競(jìng)爭(zhēng)資源不激烈,兩者的性能是差不多的,而當(dāng)競(jìng)爭(zhēng)資源非常激烈時(shí)(即有大量線程同時(shí)競(jìng)爭(zhēng)),此時(shí)ReentrantLock的性能要遠(yuǎn)遠(yuǎn)優(yōu)于synchronized。所以說,在具體使用時(shí)要根據(jù)適當(dāng)情況選擇。
在JDK1.5中,synchronized是性能低效的。因?yàn)檫@是一個(gè)重量級(jí)操作,它對(duì)性能最大的影響是阻塞的是實(shí)現(xiàn),掛起線程和恢復(fù)線程的操作都需要轉(zhuǎn)入內(nèi)核態(tài)中完成,這些操作給系統(tǒng)的并發(fā)性帶來了很大的壓力。相比之下使用Java提供的ReentrankLock對(duì)象,性能更高一些。到了JDK1.6,發(fā)生了變化,對(duì)synchronize加入了很多優(yōu)化措施,有自適應(yīng)自旋,鎖消除,鎖粗化,輕量級(jí)鎖,偏向鎖等等。導(dǎo)致在JDK1.6上synchronize的性能并不比Lock差。官方也表示,他們也更支持synchronize,在未來的版本中還有優(yōu)化余地,所以還是提倡在synchronized能實(shí)現(xiàn)需求的情況下,優(yōu)先考慮使用synchronized來進(jìn)行同步
http://www.itdecent.cn/p/96c89e6e7e90
------------------------------版本二---------------------------------
一、兩者的共同點(diǎn):
1)協(xié)調(diào)多線程對(duì)共享對(duì)象、變量的訪問
2)可重入,同一線程可以多次獲得同一個(gè)鎖
3)都保證了可見性和互斥性
兩者的不同點(diǎn):
1)ReentrantLock顯示獲得、釋放鎖,synchronized隱式獲得釋放鎖
2)ReentrantLock可響應(yīng)中斷(通過lock.lockInterruptibly()來實(shí)現(xiàn)這個(gè)機(jī)制)、可輪回,synchronized是不可以響應(yīng)中斷的,為處理鎖的不可用性提供了更高的靈活性
3)ReentrantLock是API級(jí)別的,synchronized是JVM級(jí)別的
4)ReentrantLock可以實(shí)現(xiàn)公平鎖
5)ReentrantLock通過Condition可以綁定多個(gè)條件,用來實(shí)現(xiàn)分組喚醒需要喚醒的線程們,而不是像synchronized要么隨機(jī)喚醒一個(gè)線程要么喚醒全部線程。
6)底層實(shí)現(xiàn)不一樣, synchronized是同步阻塞,使用的是悲觀并發(fā)策略,lock是同步非阻塞,采用的是樂觀并發(fā)策略
三、雖然ReentrantLock可以提供比synchronized更高級(jí)的功能,但是仍不能替換synchronized
《java并發(fā)編程實(shí)戰(zhàn)》上說是因?yàn)槿绻褂胷eentrantlock時(shí),你沒有釋放鎖,很難追蹤到最初發(fā)生錯(cuò)誤的位置,因?yàn)闆]有記錄應(yīng)該釋放鎖的位置和時(shí)間。網(wǎng)上找了一下,沒有找到其他比較合理的答案,先暫且記住吧
幾個(gè)方法:
1) boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
time:等待鎖定的最長(zhǎng)時(shí)間
unit: 時(shí)間單位
這個(gè)方法起到了定時(shí)鎖的作用,如果在指定時(shí)間內(nèi)沒有獲取到鎖,將會(huì)返回false
應(yīng)用:具有時(shí)間限制的操作時(shí)使用
四、什么時(shí)候選擇使用synchronized,什么使用選擇使用ReentrantLock
僅當(dāng)synchronized不能滿足時(shí)才使用ReentrantLockk,因?yàn)槭褂?b>ReentrantLock要非常小心,不釋放鎖將影響其他需要該鎖的代碼塊運(yùn)行
不能使用synchronized不滿足的情形:
1)公平性
2)可中斷
4)分塊結(jié)構(gòu)的加鎖,比如jdk1.7ConcurrentHashMap的分段鎖(目前還不是提別理解這個(gè),先記住這個(gè)例子,后頭補(bǔ)充)
五、synchronized和ReentrantLock兩者之間性能的比較
從jdk1.5以后,性能就差不多了,因?yàn)閖vm對(duì)synchronized進(jìn)行了很多優(yōu)化