Setup
dependencies {
implementation("org.jetbrains.kotlinx:atomicfu:0.17.2")
}用法
val atomicInt = atomic(123)
atomicInt.value // 读
atomicInt.value = 1234 // 写必须确保所有的操作都是原子的。亦即只能通过 atomicfu
已经提供的方法操作。
如果只需要读/写操作,可以使用代理:
var delegatedAtomic by atomic(1231)
delegatedAtomic // 读
delegatedAtomic = 123 // 写但切记只能通过 atomicfu
已经提供的方法操作,原子性需要小心维护,以下的写法是完全错误的:
var delegatedAtomic by atomic(123)
if (delegatedAtomic == 1) delegatedAtomic = 1000正确的写法:
val atomicInt = atomic(123)
atomicInt.compareAndSet(expect = 1, update = 1000)
// 或... 使用高阶函数
atomicInt.getAndUpdate { if (it == 1) 1000 else it }无需加锁的函数式写法:
fun push(v: Value) = top.update { cur -> Node(v, cur) }
fun pop(): Value? = top.getAndUpdate { cur -> cur?.next }?.valueInt 和 Long 也有
getAndIncrement, incrementAndGet,
getAndAdd, addAndGet 方法,以及对
+= -= 的操作符重载。
注意事项
避免使用未提供的操作
再次强调,原子性并不凭空产生。你需要使用已经提供的原子性 API。
- 不要使用局部变量存储 atomic 变量的引用
- 不要使用复杂的表达式,任何有分支的语句都会造成问题,需要时请使用诸如
atomicValue.update的方法。
隐藏内部实现
如你所见,维护线程安全并不容易,所以不要向外泄漏引用。
需要向外公开API时,请像这样:
private val _foo = atomic(100) // 内部原子变量,以 _ 开头
public var foo: Int by _foo // 公开代理属性 (val/var)