Android中的AtomicLong原理、使用與實(shí)戰(zhàn)指南
本文結(jié)合生產(chǎn)環(huán)境實(shí)戰(zhàn)案例,帶你徹底搞懂AtomicLong在Android多線程開(kāi)發(fā)中的應(yīng)用。全文包含大量Kotlin代碼示例,建議收藏備用。
一、為什么需要AtomicLong?
在Android開(kāi)發(fā)中,當(dāng)多個(gè)線程同時(shí)操作同一個(gè)Long型變量時(shí),你可能會(huì)遇到這樣的詭異場(chǎng)景:
var counter = 0L fun increment() { // 這個(gè)操作在并發(fā)場(chǎng)景下會(huì)出錯(cuò)! counter++ }
這個(gè)簡(jiǎn)單的自增操作,編譯后會(huì)變成多條JVM指令(ILOAD, LCONST_1, LADD, LSTORE),根本不是原子操作!普通Long變量在多線程環(huán)境下存在安全隱患。
二、AtomicLong的核心原理
2.1 CAS機(jī)制
AtomicLong底層采用CAS(Compare And Swap)算法:
// 偽代碼實(shí)現(xiàn) fun incrementAndGet(): Long { while(true) { val current = get() val next = current + 1 if (compareAndSet(current, next)) { return next } } }
這個(gè)過(guò)程就像超市寄存柜——只有當(dāng)柜子里的物品和預(yù)期一致時(shí),才能放入新物品。通過(guò)自旋重試機(jī)制保證原子性,但要注意CPU資源消耗。
2.2 內(nèi)存可見(jiàn)性
通過(guò)volatile關(guān)鍵字保證修改的可見(jiàn)性:
// JDK源碼片段 private volatile long value; public final long get() { return value; }
這個(gè)設(shè)計(jì)讓所有線程都能立即看到最新值。
三、AtomicLong的基本使用
3.1 初始化方式
// 初始值為0 val atomicCounter = AtomicLong() // 帶初始值 val pageViewCounter = AtomicLong(1000)
3.2 常用方法詳解
方法名 | 等價(jià)操作 | 說(shuō)明 |
---|---|---|
get() | val = x | 獲取當(dāng)前值 |
set(newValue) | x = new | 直接賦值(慎用?。?/td> |
getAndIncrement() | x++ | 先返回舊值再+1(適合計(jì)數(shù)統(tǒng)計(jì)) |
incrementAndGet() | ++x | 先+1再返回新值 |
compareAndSet(expect, update) | CAS操作 | 核心方法,成功返回true |
四、AtomicLong的適用場(chǎng)景
? 推薦使用場(chǎng)景
- 低并發(fā)的精確計(jì)數(shù)器(如頁(yè)面訪問(wèn)量統(tǒng)計(jì))
- 需要保證原子性的狀態(tài)標(biāo)記(如下載進(jìn)度百分比)
- 需要配合其他原子類構(gòu)建復(fù)雜邏輯
不推薦場(chǎng)景
- 超高并發(fā)計(jì)數(shù)器(考慮LongAdder)
- 需要保證連續(xù)性的操作(如ID生成)
五、生產(chǎn)環(huán)境實(shí)戰(zhàn)案例
5.1 頁(yè)面訪問(wèn)量統(tǒng)計(jì)
class PageVisitTracker { private val visitCount = AtomicLong(0) // 注意:這個(gè)方法要在后臺(tái)線程調(diào)用 fun trackVisit() { visitCount.incrementAndGet() if (visitCount.get() % 100 == 0L) { uploadToServer() // 每100次上報(bào)服務(wù)器 } } fun getVisitCount() = visitCount.get() }
5.2 下載進(jìn)度同步
class DownloadManager { private val progress = AtomicLong(0) fun updateProgress(bytes: Long) { progress.addAndGet(bytes) val current = progress.get() if (current % (1024 * 1024) == 0L) { // 每MB更新UI runOnUiThread { updateProgressBar(current) } } } }
六、性能優(yōu)化建議
- 避免濫用get():頻繁調(diào)用get()會(huì)導(dǎo)致緩存失效
- 慎用lazySet:只有在明確不需要立即可見(jiàn)時(shí)使用
- 注意自旋消耗:高并發(fā)下考慮退避策略或改用LongAdder
七、與LongAdder的抉擇
當(dāng)遇到類似需求時(shí):
when { writeQPS < 1000 -> AtomicLong() writeQPS > 5000 -> LongAdder() else -> 根據(jù)業(yè)務(wù)精度要求選擇 }
八、常見(jiàn)坑點(diǎn)排查
8.1 原子性誤解
錯(cuò)誤用法:
if (atomicValue.get() > 100) { atomicValue.set(0) // 這兩個(gè)操作不是原子的! }
正確姿勢(shì):
while (true) { val current = atomicValue.get() if (current <= 100) break if (atomicValue.compareAndSet(current, 0)) break }
8.2 數(shù)值溢出問(wèn)題
val MAX = Long.MAX_VALUE val counter = AtomicLong(MAX - 10) repeat(20) { counter.incrementAndGet() // 最后會(huì)變成Long.MIN_VALUE }
九、進(jìn)階技巧
9.1 配合Kotlin擴(kuò)展函數(shù)
fun AtomicLong.update(action: (Long) -> Long) { while (true) { val current = get() val newValue = action(current) if (compareAndSet(current, newValue)) return } } // 使用示例 atomicCounter.update { it * 2 }
9.2 性能監(jiān)控方案
class MonitoredAtomicLong( initialValue: Long ) : AtomicLong(initialValue) { private val casFailureCount = AtomicInteger() override fun compareAndSet(expect: Long, update: Long): Boolean { val success = super.compareAndSet(expect, update) if (!success) casFailureCount.incrementAndGet() return success } fun printStats() { Log.d("AtomicStats", "CAS失敗次數(shù):${casFailureCount.get()}") } }
十、總結(jié)
AtomicLong像一把精準(zhǔn)的手術(shù)刀:
- 優(yōu)勢(shì):精確控制、API豐富、低延遲
- 局限:高并發(fā)下性能衰減明顯(當(dāng)CAS失敗率>30%時(shí)需警惕)
到此這篇關(guān)于Android中的AtomicLong原理、使用與實(shí)戰(zhàn)指南的文章就介紹到這了,更多相關(guān)Android AtomicLong原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android中的Looper對(duì)象詳細(xì)介紹
這篇文章主要介紹了Android中的Looper對(duì)象,需要的朋友可以參考下2014-02-02Android實(shí)現(xiàn)橫豎屏切換的實(shí)例代碼
本篇文章主要介紹了Android實(shí)現(xiàn)橫豎屏切換的實(shí)例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06Android開(kāi)發(fā)Compose框架使用開(kāi)篇
這篇文章主要為大家介紹了Android開(kāi)發(fā)Compose框架使用開(kāi)篇,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09Android自定義相機(jī)界面的實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了Android自定義相機(jī)界面的實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11解決 INSTALL FAILED CONFLICTING PROVIDER的問(wèn)題方法
這篇文章主要介紹了解決 INSTALL FAILED CONFLICTING PROVIDER的問(wèn)題方法的相關(guān)資料,需要的朋友可以參考下2017-02-02Android自定義ViewGroup實(shí)現(xiàn)標(biāo)簽流效果
這篇文章主要為大家詳細(xì)介紹了Android自定義ViewGroup實(shí)現(xiàn)標(biāo)簽流效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06