日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

我們知道悲觀鎖在高并發(fā)的場景下,激烈的鎖競爭會造成線程阻塞,大量阻塞線程會導(dǎo)致系統(tǒng)上下文切換,增加系統(tǒng)的性能開銷。那么有沒有可能實現(xiàn)一種非阻塞的鎖機制來保證線程的安全呢?答案是肯定的。今天我就帶你學(xué)習(xí)下樂觀鎖的優(yōu)化方法,看看怎么使用才能發(fā)揮它最大的價值。

一 什么是樂觀鎖

樂觀鎖,顧名思義,就是說在操作共享資源時,它總是抱著樂觀的態(tài)度進(jìn)行,它認(rèn)為自己可以成功的完成操作。但實際上,當(dāng)多個線程同時操作一個共享資源時,只有一個線程會成功,那么失敗的線程呢?它們不會像悲觀鎖一樣,在操作系統(tǒng)中掛起,而僅僅是返回,并且系統(tǒng)允許失敗的線程重試,也允許自動放棄退出操作。

所以,樂觀鎖相比悲觀鎖來說,不會帶來死鎖,饑餓等活性故障問題,線程間的相互影響也遠(yuǎn)遠(yuǎn)比悲觀鎖要小。更為重要的是,樂觀鎖沒有因鎖競爭造成的系統(tǒng)開銷,所以在性能上也是更勝一籌。

二 樂觀鎖的實現(xiàn)原理

CAS是實現(xiàn)樂觀鎖的核心算法,它包含了3個參數(shù):V(需要更新的變量),E(預(yù)期值)和N(最新值)。

1.CAS如何實現(xiàn)原子操作

在JDK中的concurrent包中,atomic路徑下的類都是基于CAS實現(xiàn)的。AtomicInteger就是基于CAS實現(xiàn)的一個線程安全的整型類。下面我們通過源碼來了解下如何使用CAS實現(xiàn)原子操作。

我們可以看到AtomicInteger的自增方法是使用了Unsafe的getAndAddInt方法,顯然AtomicInteger依賴于本地方法Unsafe類,Unsafe類中的操作方法會調(diào)用CPU底層指令實現(xiàn)原子操作。


 

2.處理器如何實現(xiàn)原子操作

CAS是調(diào)用處理器底層指令來實現(xiàn)原子操作,那么處理器底層又是如何實現(xiàn)原子操作的呢?

處理器和物理內(nèi)存之間的通信速度要遠(yuǎn)慢于處理器間的處理速度,所以處理器有自己的內(nèi)部緩存。如下圖所示,在執(zhí)行操作時,頻繁使用的內(nèi)存數(shù)據(jù)會緩存在處理器的L1,L2和L3高速緩存中,以加快頻繁讀取的速度。


 

三 優(yōu)化CAS樂觀鎖

雖然樂觀鎖在并發(fā)性能上要比悲觀蘇優(yōu)越,但是在于寫大于讀的操作場景下,CAS失敗的可能性會增大,如果不放棄此次CAS操作,就需要循環(huán)做CAS重試,這無疑會長時間地占用CPU。

在JAVA1.7中,通過以下代碼我們可以看到:AtomicInteger的getAndSet方法中使用了for循環(huán)不斷重試CAS操作,如果長時間不成功,就會給CPU帶來非常大的執(zhí)行開銷。到了Java8,for循環(huán)雖然被去掉了,但是我們反編譯Unsafe類時就可以發(fā)現(xiàn)該循環(huán)其實是被封裝在了Unsafe類中,CPU的執(zhí)行開銷依然存在。


 

JDK1.8中,Java提供了一個新的原子類LongAdder,LongAdder在高并發(fā)的場景下比AtomicInteger和AtomicLong的性能更好,代價就是會消耗更多的內(nèi)存空間。

LongAdder內(nèi)部由一個base變量和一個cell[]數(shù)組組成。當(dāng)只有一個寫線程,沒有競爭的情況下,LongAdder會直接使用base變量作為原子操作變量,通過CAS操作修改變量;當(dāng)有多個寫線程競爭的情況下,除了占用base變量的一個寫線程之外,其它各個線程會將修改的變量寫入到自己的槽cell[]數(shù)組中,最終結(jié)果可通過公式計算得出:


 

四 總結(jié)

在日常開發(fā)中,使用樂觀鎖最常見的場景就是數(shù)據(jù)庫的更新操作了。為了保證操作數(shù)據(jù)庫的原子性,我們常常會為每一條數(shù)據(jù)定義一個版本號,并在更新前獲取到它,到了更新數(shù)據(jù)庫的時候,還要判斷下已經(jīng)獲取的版本號是否被更新過,如果沒有,則執(zhí)行該操。

CAS樂觀鎖在平常使用時比較受限,它只能保證單個變量操作的原子性,當(dāng)涉及到多個變量時,CAS就無能為力了,但前兩講講到的悲觀鎖可以通過對整個代碼塊加鎖來做到這點。

CAS樂觀鎖在高并發(fā)寫大于讀的場景下,大部分線程的原子操作會失敗,失敗后的線程將會不斷重試CAS原子操作,這樣就會導(dǎo)致大量線程長時間地占用CPU資源,給系統(tǒng)帶來很大的性能開銷。在JDK1.8中,Java新增了一個原子類LongAdder,它使用了空間換時間的方法,解決了上訴問題。

最近的這幾講中,我詳細(xì)的講解了基于JVM實現(xiàn)的同步鎖Sychronized,AQS實現(xiàn)的同步鎖Lock以及CAS實現(xiàn)的樂觀鎖。相信你也很好奇,這三種鎖,到底哪一種的性能最好,現(xiàn)在我們來對比一下不同實現(xiàn)方式下的鎖的性能。

鑒于脫離實際業(yè)務(wù)場景的性能對比測試結(jié)果沒有意義,我們可以分別在“讀多寫少”,“讀少寫多”,“讀寫差不多”這三種場景下進(jìn)行測試。又因為鎖的性能還與競爭的激烈程度有關(guān),所以除此之外,我們還將做三種鎖在不同競爭級別下的性能測試。

綜合上述條件,我將對四種模式下的五個鎖Sychronized,ReentrantLock,ReentrantReadWriteLock,StampedLock以及樂觀鎖LongAdder進(jìn)行壓測。


 

通過以上結(jié)果,我們可以發(fā)現(xiàn):在讀大于寫的場景下,讀寫鎖ReentrantReadWriteLock,StampedLock以及樂觀鎖的讀寫性能是最好的;在寫大于讀的場景下,樂觀鎖的性能是最好的,其它4種鎖的性能則差不多;在讀和寫差不多的場景下,兩種讀寫鎖以及樂觀鎖的性能要優(yōu)于Sychronized和ReentrantLock。

分享到:
標(biāo)簽:樂觀
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運動步數(shù)有氧達(dá)人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定