偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

悲觀鎖與樂(lè)觀鎖的實(shí)現(xiàn)(詳情圖解)

開(kāi)發(fā) 前端
這篇文章講解了悲觀鎖與樂(lè)觀鎖的區(qū)別,以及實(shí)現(xiàn)場(chǎng)景,不管是悲觀鎖還是樂(lè)觀鎖都是人們定義出來(lái)的概念,是一種思想。

[[390414]]

一、前言

1、在了解悲觀鎖和樂(lè)觀鎖之前,我們先了解一下什么是鎖,為什么要用到鎖?

2、技術(shù)來(lái)源于生活,鎖不僅在程序中存在,在現(xiàn)實(shí)中我們也隨處可見(jiàn),例如我們上下班打卡的指紋鎖,保險(xiǎn)柜上的密碼鎖,以及我們我們登錄的用戶(hù)名和密碼也是一種鎖,生活中用到鎖可以保護(hù)我們?nèi)松戆踩?指紋鎖)、財(cái)產(chǎn)安全(保險(xiǎn)柜密碼鎖)、信息安全(用戶(hù)名密碼鎖),讓我們更放心的去使用和生活,因?yàn)橛墟i,我們不用去擔(dān)心個(gè)人的財(cái)產(chǎn)和信息泄露。

3、而程序中的鎖,則是用來(lái)保證我們數(shù)據(jù)安全的機(jī)制和手段,例如當(dāng)我們有多個(gè)線程去訪問(wèn)修改共享變量的時(shí)候,我們可以給修改操作加鎖(syncronized)。當(dāng)多個(gè)用戶(hù)修改表中同一數(shù)據(jù)時(shí),我們可以給該行數(shù)據(jù)上鎖(行鎖)。因此,當(dāng)程序中可能出現(xiàn)并發(fā)的情況時(shí),我們就需要通過(guò)一定的手段來(lái)保證在并發(fā)情況下數(shù)據(jù)的準(zhǔn)確性,通過(guò)這種手段保證了當(dāng)前用戶(hù)和其他用戶(hù)一起操作時(shí),所得到的結(jié)果和他單獨(dú)操作時(shí)的結(jié)果是一樣的

4、沒(méi)有做好并發(fā)控制,就可能導(dǎo)致臟讀、幻讀和不可重復(fù)讀等問(wèn)題,如下圖所示:

由于并發(fā)操作,如果沒(méi)有加鎖進(jìn)行并發(fā)控制,數(shù)據(jù)庫(kù)的最終的一條數(shù)據(jù)可能為3也有可能為5,導(dǎo)致數(shù)值不準(zhǔn)確

二、悲觀鎖和樂(lè)觀鎖

首先我們需要清楚的一點(diǎn)就是無(wú)論是悲觀鎖還是樂(lè)觀鎖,都是人們定義出來(lái)的概念,可以認(rèn)為是一種思想。

2.1、悲觀鎖

悲觀鎖(Pessimistic Lock): 就是很悲觀,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人會(huì)修改。所以每次在拿數(shù)據(jù)的時(shí)候都會(huì)上鎖。這樣別人想拿數(shù)據(jù)就被擋住,直到悲觀鎖被釋放,悲觀鎖中的共享資源每次只給一個(gè)線程使用,其它線程阻塞,用完后再把資源轉(zhuǎn)讓給其它線程

但是在效率方面,處理加鎖的機(jī)制會(huì)產(chǎn)生額外的開(kāi)銷(xiāo),還有增加產(chǎn)生死鎖的機(jī)會(huì)。另外還會(huì)降低并行性,如果已經(jīng)鎖定了一個(gè)線程A,其他線程就必須等待該線程A處理完才可以處理

數(shù)據(jù)庫(kù)中的行鎖,表鎖,讀鎖(共享鎖),寫(xiě)鎖(排他鎖),以及syncronized實(shí)現(xiàn)的鎖均為悲觀鎖

悲觀并發(fā)控制實(shí)際上是“先取鎖再訪問(wèn)”的保守策略,為數(shù)據(jù)處理的安全提供了保證

2.2、樂(lè)觀鎖

樂(lè)觀鎖(Optimistic Lock): 就是很樂(lè)觀,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人不會(huì)修改。所以不會(huì)上鎖,但是如果想要更新數(shù)據(jù),則會(huì)在更新前檢查在讀取至更新這段時(shí)間別人有沒(méi)有修改過(guò)這個(gè)數(shù)據(jù)。如果修改過(guò),則重新讀取,再次嘗試更新,循環(huán)上述步驟直到更新成功(當(dāng)然也允許更新失敗的線程放棄操作),樂(lè)觀鎖適用于多讀的應(yīng)用類(lèi)型,這樣可以提高吞吐量

相對(duì)于悲觀鎖,在對(duì)數(shù)據(jù)庫(kù)進(jìn)行處理的時(shí)候,樂(lè)觀鎖并不會(huì)使用數(shù)據(jù)庫(kù)提供的鎖機(jī)制。一般的實(shí)現(xiàn)樂(lè)觀鎖的方式就是記錄數(shù)據(jù)版本(version)或者是時(shí)間戳來(lái)實(shí)現(xiàn),不過(guò)使用版本記錄是最常用的。

樂(lè)觀控制相信事務(wù)之間的數(shù)據(jù)競(jìng)爭(zhēng)(data race)的概率是比較小的,因此盡可能直接做下去,直到提交的時(shí)候才去鎖定,所以不會(huì)產(chǎn)生任何鎖和死鎖。

三、鎖的實(shí)現(xiàn)

悲觀鎖阻塞事務(wù)、樂(lè)觀鎖回滾重試:它們各有優(yōu)缺點(diǎn),不要認(rèn)為一種一定好于另一種。像樂(lè)觀鎖適用于寫(xiě)比較少的情況下,即沖突真的很少發(fā)生的時(shí)候,這樣可以省去鎖的開(kāi)銷(xiāo),加大了系統(tǒng)的整個(gè)吞吐量。但如果經(jīng)常產(chǎn)生沖突,上層應(yīng)用會(huì)不斷的進(jìn)行重試,這樣反倒是降低了性能,所以這種情況下用悲觀鎖就比較合適。

3.1 悲觀鎖的實(shí)現(xiàn)方式

場(chǎng)景:

  • 有用戶(hù)A和用戶(hù)B,在同一家店鋪去購(gòu)買(mǎi)同一個(gè)商品,但是商品的可購(gòu)買(mǎi)數(shù)量只有一個(gè)

下面是這個(gè)店鋪的商品表t_goods結(jié)構(gòu)和表中的數(shù)據(jù):

在不加鎖的情況下,如果用戶(hù)A和用戶(hù)B同時(shí)下單,就會(huì)報(bào)錯(cuò)。

悲觀鎖的實(shí)現(xiàn),往往依靠數(shù)據(jù)庫(kù)提供的鎖機(jī)制,在數(shù)據(jù)庫(kù)中,我們?nèi)绾斡帽^鎖去解決這個(gè)事情呢?

  1. 加入當(dāng)用戶(hù)A對(duì)下單購(gòu)買(mǎi)商品(臭豆腐)的時(shí)候,先去嘗試對(duì)該數(shù)據(jù)(臭豆腐)加上悲觀鎖
  2. 加鎖失?。赫f(shuō)明商品(臭豆腐)正在被其他事務(wù)進(jìn)行修改,當(dāng)前查詢(xún)需要等待或者拋出異常,具體返回的方式需要由開(kāi)發(fā)者根據(jù)具體情況去定義
  3. 加鎖成功:對(duì)商品(臭豆腐)進(jìn)行修改,也就是只有用戶(hù)A能買(mǎi),用戶(hù)B想買(mǎi)(臭豆腐)就必須一直等待。當(dāng)用戶(hù)A買(mǎi)好后,用戶(hù)B再想去買(mǎi)(臭豆腐)的時(shí)候會(huì)發(fā)現(xiàn)數(shù)量已經(jīng)為0,那么B看到后就會(huì)放棄購(gòu)買(mǎi)
  4. 在此期間如果有其他對(duì)該數(shù)據(jù)(臭豆腐)做修改或加鎖的操作,都會(huì)等待我們解鎖后或者直接拋出異常

那么如何加上悲觀鎖呢?我們可以通過(guò)以下語(yǔ)句給id=2的這行數(shù)據(jù)加上悲觀鎖,首先關(guān)閉MySQL數(shù)據(jù)庫(kù)的自動(dòng)提交屬性。因?yàn)镸ySQL默認(rèn)使用autocommit模式,也就是說(shuō),當(dāng)我們執(zhí)行一個(gè)更新操作后,MySQL會(huì)立刻將結(jié)果進(jìn)行提交, (sql語(yǔ)句:setautocommit=0)

悲觀鎖加鎖sql語(yǔ)句:

  1. select num from t_goods where id = 2 for update 

我們通過(guò)開(kāi)啟mysql的兩個(gè)會(huì)話(huà),也就是兩個(gè)命令行來(lái)演示:

事務(wù)A:我們可以看到數(shù)據(jù)是立刻馬上就可以查詢(xún)出來(lái),num=1

事務(wù)B:我們是可以看到,事務(wù)B會(huì)一直等待事務(wù)A釋放鎖。如果事務(wù)A長(zhǎng)期不釋放鎖,那么最終事務(wù)B將會(huì)報(bào)錯(cuò),報(bào)錯(cuò)如下圖所示,表示語(yǔ)句已被鎖住。

現(xiàn)在我們讓事務(wù)A執(zhí)行命令去修改數(shù)據(jù),讓臭豆腐的數(shù)量減一,然后查看修改后的數(shù)據(jù),最后commit,結(jié)束事務(wù)

我們可以看到當(dāng)我們事務(wù)A執(zhí)行完成之后,臭豆腐的庫(kù)存只有0個(gè)了,這個(gè)時(shí)候我們用戶(hù)B再來(lái)購(gòu)買(mǎi)這個(gè)臭豆腐的時(shí)候就會(huì)發(fā)現(xiàn),最后一個(gè)臭豆腐已經(jīng)被用戶(hù)A購(gòu)買(mǎi)完了,那么用戶(hù)B只能放棄購(gòu)買(mǎi)臭豆腐了。

通過(guò)悲觀鎖我們可以解決因?yàn)樯唐穾?kù)存不足,導(dǎo)致的商品超出庫(kù)存的售賣(mài)。

3.1 樂(lè)觀鎖的實(shí)現(xiàn)方式

對(duì)于上面的應(yīng)用場(chǎng)景,我們應(yīng)該怎么用樂(lè)觀鎖去解決呢?在上面的樂(lè)觀鎖中,我們有提到使用版本號(hào)(version)來(lái)解決,所以我們需要在t_goods加上版本號(hào),調(diào)整后的sql表結(jié)構(gòu)如下:

具體操作步驟如下:

1、首先用戶(hù)A和用戶(hù)B同時(shí)將臭豆腐(id=2)的數(shù)據(jù)查出來(lái)

2、然后用戶(hù)A先買(mǎi),用戶(hù)A將(id=1和version=0)作為條件進(jìn)行數(shù)據(jù)更新,將數(shù)量-1,并且將版本號(hào)+1。此時(shí)版本號(hào)變?yōu)?。用戶(hù)A此時(shí)就完成了商品的購(gòu)買(mǎi)

3、 用戶(hù)B開(kāi)始買(mǎi),用戶(hù)B也將(id=1和version=0)作為條件進(jìn)行數(shù)據(jù)更新

4、更新完后,發(fā)現(xiàn)更新的數(shù)據(jù)行數(shù)為0,此時(shí)就說(shuō)明已經(jīng)有人改動(dòng)過(guò)數(shù)據(jù),此時(shí)就應(yīng)該提示用戶(hù)B重新查看最新數(shù)據(jù)購(gòu)買(mǎi)

1、首先我們開(kāi)啟兩個(gè)會(huì)話(huà)窗口,輸入查詢(xún)語(yǔ)句:selectnumfromt_goodswhere id=2

事務(wù)A:

事務(wù)B:

這個(gè)時(shí)候事務(wù)A和事務(wù)B同時(shí)獲取相同的數(shù)據(jù)

2、此時(shí)事務(wù)A進(jìn)行更新數(shù)據(jù)的操作,然后在查詢(xún)更新后的數(shù)據(jù)

這個(gè)時(shí)候我們可以看到事務(wù)A更新成功,并且?guī)齑?1 版本號(hào)+1成功

2、此時(shí)事務(wù)B進(jìn)行更新數(shù)據(jù)的操作,然后在查詢(xún)更新后的數(shù)據(jù)

可以看到最終修改的時(shí)候失敗,數(shù)據(jù)沒(méi)有改變。此時(shí)就需要我們告知用戶(hù)B重新處理

3.1.1 CAS

說(shuō)到樂(lè)觀鎖,就必須提到一個(gè)概念:CAS 什么是CAS呢?Compare-and-Swap,即比較并替換,也有叫做Compare-and-Set的,比較并設(shè)置。1、比較:讀取到了一個(gè)值A(chǔ),在將其更新為B之前,檢查原值是否仍為A(未被其他線程改動(dòng))。2、設(shè)置:如果是,將A更新為B,結(jié)束。[1]如果不是,則什么都不做。上面的兩步操作是原子性的,可以簡(jiǎn)單地理解為瞬間完成,在CPU看來(lái)就是一步操作。有了CAS,就可以實(shí)現(xiàn)一個(gè)樂(lè)觀鎖,允許多個(gè)線程同時(shí)讀取(因?yàn)楦緵](méi)有加鎖操作),但是只有一個(gè)線程可以成功更新數(shù)據(jù),并導(dǎo)致其他要更新數(shù)據(jù)的線程回滾重試。CAS利用CPU指令,從硬件層面保證了操作的原子性,以達(dá)到類(lèi)似于鎖的效果。

Java中真正的CAS操作調(diào)用的native方法因?yàn)檎麄€(gè)過(guò)程中并沒(méi)有“加鎖”和“解鎖”操作,因此樂(lè)觀鎖策略也被稱(chēng)為無(wú)鎖編程。換句話(huà)說(shuō),樂(lè)觀鎖其實(shí)不是“鎖”,它僅僅是一個(gè)循環(huán)重試CAS的算法而已!

四、如何選擇

悲觀鎖阻塞事務(wù),樂(lè)觀鎖回滾重試,它們各有優(yōu)缺點(diǎn),不要認(rèn)為一種一定好于另一種。像樂(lè)觀鎖適用于寫(xiě)比較少的情況下,即沖突真的很少發(fā)生的時(shí)候,這樣可以省去鎖的開(kāi)銷(xiāo),加大了系統(tǒng)的整個(gè)吞吐量。

但如果經(jīng)常產(chǎn)生沖突,上層應(yīng)用會(huì)不斷的進(jìn)行重試,這樣反倒是降低了性能,所以這種情況下用悲觀鎖就比較合適。

注意點(diǎn):

1、樂(lè)觀鎖并未真正加鎖,所以效率高。一旦鎖的粒度掌握不好,更新失敗的概率就會(huì)比較高,容易發(fā)生業(yè)務(wù)失敗。

2、悲觀鎖依賴(lài)數(shù)據(jù)庫(kù)鎖,效率低。更新失敗的概率比較低。

五、總結(jié)

這篇文章講解了悲觀鎖與樂(lè)觀鎖的區(qū)別,以及實(shí)現(xiàn)場(chǎng)景,不管是悲觀鎖還是樂(lè)觀鎖都是人們定義出來(lái)的概念,是一種思想,

 

責(zé)任編輯:姜華 來(lái)源: 牧小農(nóng)
相關(guān)推薦

2024-05-17 09:33:22

樂(lè)觀鎖CASversion

2023-02-23 10:32:52

樂(lè)觀鎖

2024-01-29 01:08:01

悲觀鎖遞歸鎖讀寫(xiě)鎖

2024-07-25 09:01:22

2025-04-23 08:45:00

悲觀鎖樂(lè)觀鎖并發(fā)控制機(jī)制

2024-09-03 15:14:42

2023-07-05 08:18:54

Atomic類(lèi)樂(lè)觀鎖悲觀鎖

2011-08-18 13:44:42

Oracle悲觀鎖樂(lè)觀鎖

2019-05-05 10:15:42

悲觀鎖樂(lè)觀鎖數(shù)據(jù)安全

2019-04-19 09:48:53

樂(lè)觀鎖悲觀鎖數(shù)據(jù)庫(kù)

2019-11-28 16:00:06

重入鎖讀寫(xiě)鎖樂(lè)觀鎖

2009-09-25 16:43:44

Hibernate悲觀Hibernate樂(lè)觀

2019-01-04 11:18:35

獨(dú)享鎖共享鎖非公平鎖

2020-07-06 08:03:32

Java悲觀鎖樂(lè)觀鎖

2024-01-05 16:43:30

數(shù)據(jù)庫(kù)線程

2018-07-31 10:10:06

MySQLInnoDB死鎖

2023-08-17 14:10:11

Java開(kāi)發(fā)前端

2020-09-16 07:56:28

多線程讀寫(xiě)鎖悲觀鎖

2010-08-18 09:00:38

數(shù)據(jù)庫(kù)

2020-10-22 08:21:37

樂(lè)觀鎖、悲觀鎖和MVC
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)