本文结合生产环境实战案例,带你彻底搞懂AtomicLong在Android多线程开发中的应用。全文包含大量Kotlin代码示例,建议收藏备用。
在Android开发中,当多个线程同时操作同一个Long型变量时,你可能会遇到这样的诡异场景:
var counter = 0L
fun increment() {
// 这个操作在并发场景下会出错!
counter++
}
这个简单的自增操作,编译后会变成多条JVM指令(ILOAD, LCONST_1, LADD, LSTORE),根本不是原子操作!普通Long变量在多线程环境下存在安全隐患。
AtomicLong底层采用CAS(Compare And Swap)算法:
// 伪代码实现
fun incrementAndGet(): Long {
while(true) {
val current = get()
val next = current + 1
if (compareAndSet(current, next)) {
return next
}
}
}
这个过程就像超市寄存柜——只有当柜子里的物品和预期一致时,才能放入新物品。通过自旋重试机制保证原子性,但要注意CPU资源消耗。
通过volatile关键字保证修改的可见性:
// JDK源码片段
private volatile long value;
public final long get() {
return value;
}
这个设计让所有线程都能立即看到最新值。
// 初始值为0
val atomicCounter = AtomicLong()
// 带初始值
val pageViewCounter = AtomicLong(1000)
方法名 | 等价操作 | 说明 |
---|---|---|
get() | val = x | 获取当前值 |
set(newValue) | x = new | 直接赋值(慎用!) |
getAndIncrement() | x++ | 先返回旧值再+1(适合计数统计) |
incrementAndGet() | ++x | 先+1再返回新值 |
compareAndSet(expect, update) | CAS操作 | 核心方法,成功返回true |
class PageVisitTracker {
private val visitCount = AtomicLong(0)
// 注意:这个方法要在后台线程调用
fun trackVisit() {
visitCount.incrementAndGet()
if (visitCount.get() % 100 == 0L) {
uploadToServer() // 每100次上报服务器
}
}
fun getVisitCount() = visitCount.get()
}
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) }
}
}
}
当遇到类似需求时:
when {
writeQPS < 1000 -> AtomicLong()
writeQPS > 5000 -> LongAdder()
else -> 根据业务精度要求选择
}
错误用法:
if (atomicValue.get() > 100) {
atomicValue.set(0) // 这两个操作不是原子的!
}
正确姿势:
while (true) {
val current = atomicValue.get()
if (current <= 100) break
if (atomicValue.compareAndSet(current, 0)) break
}
val MAX = Long.MAX_VALUE
val counter = AtomicLong(MAX - 10)
repeat(20) {
counter.incrementAndGet() // 最后会变成Long.MIN_VALUE
}
fun AtomicLong.update(action: (Long) -> Long) {
while (true) {
val current = get()
val newValue = action(current)
if (compareAndSet(current, newValue)) return
}
}
// 使用示例
atomicCounter.update { it * 2 }
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失败次数:${casFailureCount.get()}")
}
}
AtomicLong像一把精准的手术刀: