Java多線程場(chǎng)景解析volatile和AtomicLong區(qū)別原理
【摘要】
隨著多線程編程的普及,volatile和AtomicLong這兩個(gè)關(guān)鍵字被越來(lái)越多的使用。但是很多人并不理解它們的原理以及區(qū)別。今天我就來(lái)通過(guò)一個(gè)典型的場(chǎng)景,講解 volatile 和 AtomicLong 的用法、原理以及區(qū)別,希望可以幫助大家更好地使用這兩者。
我們假設(shè)有這樣一個(gè)多線程場(chǎng)景:存在一個(gè)長(zhǎng)整型變量,多個(gè)線程同時(shí)進(jìn)行讀寫(xiě)操作。為了保證線程安全,我們通常會(huì)進(jìn)行同步,但是同步操作又會(huì)影響效率。這個(gè)時(shí)候我們就可以考慮用 volatile 或者 AtomicLong 來(lái)優(yōu)化。
volatile
先說(shuō)說(shuō) volatile,它可以保證變量的可見(jiàn)性,具體來(lái)說(shuō)就是當(dāng)一個(gè)線程修改了 volatile 變量,新值對(duì)其他線程立即可見(jiàn)。這是因?yàn)関olatile變量直接操作主內(nèi)存,而不是線程的工作內(nèi)存。
java public class VolatileExample { volatile long count = 0; public void increment() { count++; } public long getCount() { return count; } }
這里通過(guò) volatile 關(guān)鍵字,可以保證多個(gè)線程都能讀取到 count 的最新的值。但是,volatile 并不能保證原子性。什么意思呢?我們來(lái)看看下面的代碼:
java public void increment() { count++; } // 這里的遞增操作并不是原子的,實(shí)際會(huì)分為三步 // 1. 讀取count值 // 2. 計(jì)算值+1 // 3. 寫(xiě)入新的值
也就是說(shuō)某一個(gè)時(shí)刻,可能有兩個(gè)線程同時(shí)讀取了 count 值,然后分別增加,這就破壞了原子性。要解決這個(gè)問(wèn)題,我們就需要 AtomicLong 了。
AtomicLong
AtomicLong 通過(guò) CAS (Compare And Swap) 算法實(shí)現(xiàn)了對(duì)長(zhǎng)整型的原子操作??匆粋€(gè)例子:
java AtomicLong atomicCount = new AtomicLong(); public void increment() { atomicCount.getAndIncrement(); }
getAndIncrement()會(huì)先獲取當(dāng)前的值,然后原子地增加,最后返回舊值。這樣多個(gè)線程調(diào)用的時(shí)候可以保證原子性。AtomicLong 的 CAS 原理是通過(guò)循環(huán)調(diào)用 CAS 指令,直到更新成功為止:
java do { // 獲取舊的預(yù)期值 oldValue = atomicCount.get(); // 用CAS指令更新值,如果預(yù)期值一樣才更新 success = compareAndSet(oldValue, oldValue + 1); // 如果失敗,繼續(xù)循環(huán)執(zhí)行CAS } while(!success);
通過(guò) CAS 不斷嘗試更新,直到成功為止。
volatile 和 AtomicLong 的區(qū)別
總結(jié)一下 volatile 和 AtomicLong 的區(qū)別
1. volatile 保證可見(jiàn)性,AtomicLong 保證原子性
2. volatile 不會(huì)對(duì)代碼產(chǎn)生線程鎖,AtomicLong 會(huì)通過(guò) CAS 產(chǎn)生線程開(kāi)銷
3. volatile 是通過(guò)直接操作主內(nèi)存實(shí)現(xiàn),AtomicLong 是通過(guò) CAS 實(shí)現(xiàn)那么什么時(shí)候該用 volatile,什么時(shí)候該用 AtomicLong 呢?
- 如果只要保證可見(jiàn)性,那用 volatile 即可。
- 如果需要原子操作,如對(duì)數(shù)字進(jìn)行遞增操作,這時(shí)就需要用 AtomicLong。
當(dāng)然,synchronized和Lock也能保證原子性,但是通過(guò) CAS 實(shí)現(xiàn)的 AtomicLong 性能會(huì)更好一些。
以上就是本文的全部?jī)?nèi)容了,通過(guò)一個(gè)典型多線程場(chǎng)景講解了 volatile 和 AtomicLong 的用法、原理以及區(qū)別。這兩個(gè)關(guān)鍵字非常有用,正確理解后可以充分利用它們帶來(lái)的優(yōu)勢(shì),更多關(guān)于 Java volatile AtomicLong的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Springboot引入攔截器并放行swagger代碼實(shí)例
這篇文章主要介紹了Springboot引入攔截器并放行swagger代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11springboot跨域訪問(wèn)cros與@CrossOrigin注解詳析
這篇文章主要給大家介紹了關(guān)于springboot跨域訪問(wèn)cros與@CrossOrigin注解的相關(guān)資料,跨域是指不同域名之間相互訪問(wèn),它是瀏覽器的同源策略造成的,是瀏覽器對(duì)JavaScript施加的安全限制,需要的朋友可以參考下2023-12-1210個(gè)SpringBoot參數(shù)驗(yàn)證你需要知道的技巧分享
參數(shù)驗(yàn)證很重要,是平時(shí)開(kāi)發(fā)環(huán)節(jié)中不可少的一部分,那么在Spring?Boot應(yīng)用中如何做好參數(shù)校驗(yàn)工作呢,本文提供了10個(gè)小技巧,你知道幾個(gè)呢2023-03-03