在科特林中使用原子布尔值是个好主意吗?

Is it good idea to use atomic boolean in kotlin?

嘿,我正在学习 kotlin 中的原子。我想知道在我的场景中使用原子布尔值是个好主意吗?有人可以建议,如何以原子方式做。

场景一不适合第一次调用

var isFirstTime = true

fun notForFirstTime(){
   if(!isFirstTime){
     jobDone()
   }
  isFirstTime = false
}

场景二 仅限第一次

var isFirstTime = true

fun onlyForFirstTime(){
   if(isFirstTime){
     jobDone()
   }
  isFirstTime = false
}

我可以用原子方式来做吗?这也是个好主意吗?

这取决于您要实现的目标。

对于场景 2,大多数时候您需要的是计算一次并在以后重复使用的值。对于此 use-case,您可以像这样使用 lazy 委托:

class MyClass {
    
    // will be computed the first time it's accessed, and then reused
    val value by lazy { computeExpensiveValue() }
}


fun computeExpensiveValue(): Int {
    // some complex stuff
    return 42
}

我从未遇到过场景 1,但在 lazy 不够用的情况下,您确实可以将原子布尔值用于 CAS 方法或锁。例如检查 kotlinx.atomicfu.

如果您使用的是 Kotlin 协程,您可能需要检查其他同步原语,例如 Mutex and Semaphore。但总的来说,最好让协程通过通道进行通信而不是共享可变状态。

不太清楚你问的是什么。但是假设你想确保一些代码只在第一次执行(或不执行)并且函数可以并发调用(因为你要求“原子”)那么答案是:不,不。您的两个代码示例都不是 thread-safe,并且可能会导致比第一个调用更多的调用以特殊方式处理。

这不是因为布尔值不是原子的,而是因为您的代码不是原子的。两个或多个并发线程可以同时检查 isFirstTime,然后其他线程会将其翻转为 false

您可以通过多种方式解决这个问题,例如使用互斥锁,但最简单和性能最好的可能是使用 compare and swap operations 之一。例如:

val isFirstTime = AtomicBoolean(true)

fun notForFirstTime(){
  if (!isFirstTime.getAndSet(false)) {
    jobDone()
  }
}

fun onlyForFirstTime(){
  if (isFirstTime.getAndSet(false)) {
    jobDone()
  }
}