新聞中心
悲觀鎖和樂(lè)觀鎖并不是某個(gè)具體的“鎖”而是一種并發(fā)編程的基本概念,是根據(jù)看待并發(fā)同步的角度;
成都創(chuàng)新互聯(lián)-成都網(wǎng)站建設(shè)公司,專注網(wǎng)站設(shè)計(jì)制作、網(wǎng)站設(shè)計(jì)、網(wǎng)站營(yíng)銷推廣,域名注冊(cè),虛擬主機(jī),網(wǎng)站托管維護(hù)有關(guān)企業(yè)網(wǎng)站制作方案、改版、費(fèi)用等問(wèn)題,請(qǐng)聯(lián)系成都創(chuàng)新互聯(lián)。
悲觀鎖和樂(lè)觀鎖是用來(lái)解決并發(fā)問(wèn)題的兩種思想,在不同的平臺(tái)有著各自的實(shí)現(xiàn)。
廢話不多,開(kāi)始講解
1、悲觀鎖
- 悲觀鎖是基于一種悲觀的態(tài)度類來(lái)防止一切數(shù)據(jù)沖突,它是以一種預(yù)防的姿態(tài)在修改數(shù)據(jù)之前把數(shù)據(jù)鎖住,然后再對(duì)數(shù)據(jù)進(jìn)行讀寫,在它釋放鎖之前任何人都不能對(duì)其數(shù)據(jù)進(jìn)行操作,直到前面一個(gè)人把鎖釋放后下一個(gè)人數(shù)據(jù)加鎖才可對(duì)數(shù)據(jù)進(jìn)行加鎖,然后才可以對(duì)數(shù)據(jù)進(jìn)行操作,一般數(shù)據(jù)庫(kù)本身鎖的機(jī)制都是基于悲觀鎖的機(jī)制實(shí)現(xiàn)的;
- 特點(diǎn):可以完全保證數(shù)據(jù)的獨(dú)占性和正確性,因?yàn)槊看握?qǐng)求都會(huì)先對(duì)數(shù)據(jù)進(jìn)行加鎖, 然后進(jìn)行數(shù)據(jù)操作,最后再解鎖,而加鎖釋放鎖的過(guò)程會(huì)造成消耗,所以性能不高;
- 悲觀鎖通常多用于寫多比較多的情況下(多寫場(chǎng)景),避免頻繁失敗和重試影響性能
2、樂(lè)觀鎖
- 樂(lè)觀鎖是對(duì)于數(shù)據(jù)沖突保持一種樂(lè)觀態(tài)度,操作數(shù)據(jù)時(shí)不會(huì)對(duì)操作的數(shù)據(jù)進(jìn)行加鎖(這使得多個(gè)任務(wù)可以并行的對(duì)數(shù)據(jù)進(jìn)行操作),只有到數(shù)據(jù)提交的時(shí)候才通過(guò)一種機(jī)制來(lái)驗(yàn)證數(shù)據(jù)是否存在沖突(一般實(shí)現(xiàn)方式是通過(guò)加版本號(hào)然后進(jìn)行版本號(hào)的對(duì)比方式實(shí)現(xiàn));
- 特點(diǎn):樂(lè)觀鎖是一種并發(fā)類型的鎖,其本身不對(duì)數(shù)據(jù)進(jìn)行加鎖通而是通過(guò)業(yè)務(wù)實(shí)現(xiàn)鎖的功能,不對(duì)數(shù)據(jù)進(jìn)行加鎖就意味著允許多個(gè)請(qǐng)求同時(shí)訪問(wèn)數(shù)據(jù),同時(shí)也省掉了對(duì)數(shù)據(jù)加鎖和解鎖的過(guò)程,這種方式因?yàn)楣?jié)省了悲觀鎖加鎖的操作,所以可以一定程度的的提高操作的性能,不過(guò)在并發(fā)非常高的情況下,會(huì)導(dǎo)致大量的請(qǐng)求沖突,沖突導(dǎo)致大部分操作無(wú)功而返而浪費(fèi)資源,所以在高并發(fā)的場(chǎng)景下,樂(lè)觀鎖的性能卻反而不如悲觀鎖;
- 樂(lè)觀鎖通常多于寫比較少的情況下(多讀場(chǎng)景),避免頻繁加鎖影響性能,大大提升了系統(tǒng)的吞吐量;
3、實(shí)現(xiàn)樂(lè)觀鎖算法
樂(lè)觀鎖一般會(huì)使用版本號(hào)機(jī)制或 CAS 算法實(shí)現(xiàn)
①版本號(hào)機(jī)制
數(shù)據(jù)表中加上一個(gè)數(shù)據(jù)版本號(hào) version 字段,表示數(shù)據(jù)被修改的次數(shù)。當(dāng)數(shù)據(jù)被修改時(shí),version 值會(huì)加一。當(dāng)線程 A 要更新數(shù)據(jù)值時(shí),在讀取數(shù)據(jù)的同時(shí)也會(huì)讀取 version 值,在提交更新時(shí),若剛才讀取到的 version 值為當(dāng)前數(shù)據(jù)庫(kù)中的 version 值相等時(shí)才更新,否則重試更新操作,直到更新成功
②CAS 算法
CAS 的思想很簡(jiǎn)單,就是用一個(gè)預(yù)期值和要更新的變量值進(jìn)行比較,兩值相等才會(huì)進(jìn)行更新;
CAS 是一個(gè)原子操作,底層依賴于一條 CPU 的原子指令
CAS 涉及到三個(gè)操作數(shù):
- V :要更新的變量值(Var)
- E :預(yù)期值(Expected)
- N :擬寫入的新值(New)
當(dāng)且僅當(dāng) V 的值等于 E 時(shí),CAS 通過(guò)原子方式用新值 N 來(lái)更新 V 的值。如果不等,說(shuō)明已經(jīng)有其它線程更新了V,則當(dāng)前線程放棄更新;
4、樂(lè)觀鎖問(wèn)題
①ABA 問(wèn)題
- 一個(gè)變量 V 初次讀取的時(shí)候是 A 值,并且在準(zhǔn)備賦值的時(shí)候檢查到它仍然是 A 值,那我們就能說(shuō)明它的值沒(méi)有被其他線程修改過(guò)了嗎?很明顯是不能的,因?yàn)樵谶@段時(shí)間它的值可能被改為其他值,然后又改回 A,那 CAS 操作就會(huì)誤認(rèn)為它從來(lái)沒(méi)有被修改過(guò)。這個(gè)問(wèn)題被稱為 CAS 操作的 "ABA"問(wèn)題;
- ABA 問(wèn)題的解決思路是在變量前面追加上版本號(hào)或者時(shí)間戳。JDK 1.5 以后的 AtomicStampedReference 類就是用來(lái)解決 ABA 問(wèn)題的,其中的 compareAndSet() 方法就是首先檢查當(dāng)前引用是否等于預(yù)期引用,并且當(dāng)前標(biāo)志是否等于預(yù)期標(biāo)志,如果全部相等,則以原子方式將該引用和該標(biāo)志的值設(shè)置為給定的更新值
②循環(huán)時(shí)間長(zhǎng)開(kāi)銷大
CAS 經(jīng)常會(huì)用到自旋操作來(lái)進(jìn)行重試,也就是不成功就一直循環(huán)執(zhí)行直到成功。如果長(zhǎng)時(shí)間不成功,會(huì)給 CPU 帶來(lái)非常大的執(zhí)行開(kāi)
③只能保證一個(gè)共享變量的原子操作
CAS 只對(duì)單個(gè)共享變量有效,當(dāng)操作涉及跨多個(gè)共享變量時(shí) CAS 無(wú)效。但是從 JDK 1.5 開(kāi)始,提供了AtomicReference類來(lái)保證引用對(duì)象之間的原子性,你可以把多個(gè)變量放在一個(gè)對(duì)象里來(lái)進(jìn)行 CAS 操作.所以我們可以使用鎖或者利用AtomicReference類把多個(gè)共享變量合并成一個(gè)共享變量來(lái)操作
網(wǎng)頁(yè)題目:面試必備之樂(lè)觀鎖與悲觀鎖
當(dāng)前地址:http://m.5511xx.com/article/dppjshi.html


咨詢
建站咨詢

