可重入鎖夷蚊、可中斷鎖构挤、公平鎖、讀寫鎖惕鼓、自旋鎖筋现。
鎖的相關(guān)概念介紹
1、可重入鎖
如果鎖具有可重入性箱歧,則稱為可重入鎖矾飞,synchronized和reentranLoke都是可重入鎖⊙叫希可重入性在我看來(lái)是表明了鎖的分配機(jī)制洒沦,基于線程的分配,而不是基于方法調(diào)用的分配价淌。比如說(shuō)當(dāng)一個(gè)線程執(zhí)行到某個(gè)synchronized方法method1時(shí)申眼,在方法method1內(nèi)部又調(diào)用了另一個(gè)synchronized方法method2,此時(shí)線程不必重新申請(qǐng)鎖蝉衣,而是可以直接執(zhí)行方法method2括尸。
假如synchronized鎖不具備可重入性,當(dāng)線程執(zhí)行到synchronized方法method1中的synchronized方法method2時(shí)病毡,線程會(huì)嘗試獲取鎖濒翻,由于synchronized鎖是這個(gè)線程本身持有的,此時(shí)線程就會(huì)陷入一種等待自身釋放鎖的無(wú)限等待中剪验。
由于synchronized鎖和lock鎖都具有可重入性肴焊,所以就不會(huì)出現(xiàn)上述情況。
2功戚、可中斷鎖
顧名思義娶眷,就是可以執(zhí)行中斷操作的鎖。
在java中啸臀,synchronized是不可中斷鎖届宠,而lock是可中斷鎖。
如果某一線程在執(zhí)行獲取鎖的過(guò)程中等待的時(shí)間過(guò)長(zhǎng)乘粒,此時(shí)這個(gè)線程不想等待了豌注,我們可以讓這個(gè)線程本身中斷等待或者讓另一線程來(lái)中斷等待,這種可以被中斷的鎖就是可中斷鎖灯萍。
3轧铁、公平鎖
公平鎖就是盡量以公平的方式來(lái)獲取鎖,比如當(dāng)一個(gè)鎖被釋放時(shí)旦棉,等待時(shí)間最久(最先申請(qǐng)鎖)的那個(gè)線程會(huì)獲得該鎖齿风,這就是公平鎖。
非公平鎖就是無(wú)法保證鎖的獲取是按照請(qǐng)求順序進(jìn)行的绑洛,這樣就可能導(dǎo)致某個(gè)或某些線程永遠(yuǎn)獲取不到鎖救斑。
在Java中,synchronized鎖是非公平鎖真屯,它無(wú)法保證等待的線程獲取鎖的順序脸候。
reentrantlock鎖和reentrantReadWirteLock鎖,他們默認(rèn)情況下是非公平鎖绑蔫,但是可以設(shè)置為公平鎖运沦。
reentrantlock類中定義了2個(gè)靜態(tài)內(nèi)部類,NotFairSync和FairSync,分別原來(lái)實(shí)現(xiàn)非公平鎖和公平鎖晾匠。我們可以在創(chuàng)建ReentrantLock對(duì)象時(shí)茶袒,來(lái)設(shè)置鎖的公平性。
給構(gòu)造函數(shù)傳入true為公平鎖凉馆,傳入false為非公平鎖薪寓。不穿默認(rèn)情況下為非公平鎖。
ReentrantReadWirteLock中也有類似的方法澜共,不過(guò)ReentrantReadWirteLock并沒(méi)有實(shí)現(xiàn)lock接口向叉,而是實(shí)現(xiàn)了ReadWirteLock接口。
4嗦董、讀寫鎖
讀寫鎖將對(duì)一個(gè)資源的訪問(wèn)分為2個(gè)鎖母谎,即一個(gè)讀鎖,一個(gè)寫鎖京革。
正因?yàn)橛辛俗x寫鎖奇唤,才使得多個(gè)線程之間的讀操作不會(huì)發(fā)生沖突幸斥。
ReadWirteLock就是讀寫鎖,它是一個(gè)接口咬扇,ReentrantReadWirteLock實(shí)現(xiàn)了這個(gè)接口甲葬。
可以通過(guò)readLock()獲取讀鎖,通過(guò)wirteLock()獲取寫鎖懈贺。
5经窖、自旋鎖
首先是一種鎖,與互斥鎖相似梭灿,基本作用是用于線程之間的同步画侣。與普通鎖不同的是,一個(gè)線程A在獲得普通鎖后堡妒,如果再有其他線程B來(lái)試圖獲取鎖配乱,那么這個(gè)線程B將會(huì)掛起(阻塞);試想下,如果2個(gè)線程資源競(jìng)爭(zhēng)不是很激烈皮迟,而處理器阻塞一個(gè)線程引起的線程上下文切換的代價(jià)可能高于線程等待資源代價(jià)的時(shí)候宪卿,那么線程B可以不放棄cpu時(shí)間片,而是在原地忙等万栅,直到鎖的持有線程釋放了這個(gè)鎖佑钾。這就是自旋鎖的原理,可見(jiàn)自旋鎖是一種非阻塞鎖烦粒。
自旋鎖可能引起的問(wèn)題休溶?
1.過(guò)多占據(jù)cpu時(shí)間:如果鎖的持有者長(zhǎng)時(shí)間不釋放該鎖,那么等待線程將會(huì)長(zhǎng)時(shí)間的占據(jù)cpu的時(shí)間片扰她,導(dǎo)致cpu資源浪費(fèi)兽掰,因此,可以設(shè)定一個(gè)時(shí)間徒役,若超過(guò)這個(gè)時(shí)間孽尽,鎖還未釋放,那么等待者放棄cpu時(shí)間片進(jìn)入阻塞忧勿。
2.死鎖問(wèn)題:有一個(gè)線程連續(xù)2次試圖獲得自旋鎖杉女,當(dāng)?shù)谝淮潍@得自旋鎖后,改線程又試圖獲取自旋鎖鸳吸,此時(shí)檢測(cè)到鎖被占用(其實(shí)是被自己占用)熏挎,那么這時(shí),該線程會(huì)一直等待自己釋放改鎖晌砾,而不能繼續(xù)執(zhí)行坎拐,這樣就引起了死鎖。因此,使用自旋鎖時(shí)程序絕不能在持有自旋鎖時(shí)調(diào)用它自己哼勇,也絕不能在遞歸調(diào)用時(shí)試圖獲取相同的自旋鎖都伪。
6、樂(lè)觀鎖/悲觀鎖
樂(lè)觀鎖與悲觀鎖不是具體什么類型的鎖积担,而是指看待并發(fā)同步的角度院溺。
悲觀鎖認(rèn)為對(duì)于同一個(gè)數(shù)據(jù)的并發(fā)操作,一定是會(huì)發(fā)生修改的磅轻,哪怕沒(méi)有修改,也會(huì)認(rèn)為修改逐虚。因此對(duì)于同一個(gè)數(shù)據(jù)的并發(fā)操作聋溜,悲觀鎖采取加鎖的形式。悲觀的認(rèn)為叭爱,不加鎖的操作一定會(huì)出問(wèn)題的撮躁。
樂(lè)觀鎖則認(rèn)為對(duì)同一個(gè)數(shù)據(jù)的并發(fā)操作,是不會(huì)發(fā)生修改的买雾。在更新數(shù)據(jù)的時(shí)候把曼,會(huì)采用嘗試更新,不斷重新的方式來(lái)更新數(shù)據(jù)鲫咽。樂(lè)觀的認(rèn)為屹篓,不加鎖的并發(fā)操作是沒(méi)有事情的寝优。
從上述我們可以看出,悲觀鎖適合寫操作非常多的場(chǎng)景叙赚,樂(lè)觀鎖適合讀操作非常多的場(chǎng)景,不加鎖會(huì)帶來(lái)大量的性能提升僚饭。
悲觀鎖在java中的使用震叮,就是利用各種鎖。
樂(lè)觀鎖在java中的使用鳍鸵,就是無(wú)鎖編程苇瓣,常常采用的是CAS算法,典型的例子就是原子類偿乖,通過(guò)CAS自旋實(shí)現(xiàn)原子操作的更新击罪。
7、偏向鎖/輕量級(jí)鎖/重量級(jí)鎖
這3種鎖是指鎖的狀態(tài)贪薪,并且是針對(duì)synchronized鎖外邓。在java5通過(guò)鎖升級(jí)機(jī)制來(lái)實(shí)現(xiàn)高性能synchronized。這3月種鎖的狀態(tài)是通過(guò)對(duì)象監(jiān)視器在對(duì)象頭中的字段來(lái)表明的古掏。
偏向鎖是指一段同步代碼塊一直被同一個(gè)線程訪問(wèn)损话,那么該線程會(huì)自動(dòng)獲取鎖,降低獲取鎖的代價(jià)。
輕量級(jí)鎖是指當(dāng)鎖為偏向鎖的時(shí)候丧枪,被另一個(gè)線程訪問(wèn)光涂,偏向鎖就會(huì)升級(jí)為輕量級(jí)鎖,其他線程會(huì)通過(guò)自旋的方式來(lái)獲取鎖拧烦,不會(huì)阻塞忘闻,提高性能。
重量級(jí)鎖是指當(dāng)鎖為輕量級(jí)鎖的時(shí)候恋博,另一個(gè)線程雖然為自旋齐佳,但自旋不會(huì)一直持續(xù)下去,當(dāng)自旋到一定次數(shù)之后债沮,還沒(méi)有獲取到鎖炼吴,就會(huì)進(jìn)入阻塞,該鎖膨脹為重量級(jí)鎖疫衩。重量級(jí)鎖會(huì)讓其他申請(qǐng)的線程進(jìn)入阻塞硅蹦,降低性能。