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


咨詢
建站咨詢

