1

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

场景 1不是第一次调用

var isFirstTime = true

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

场景 2仅适用于第一次

var isFirstTime = true

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

我可以以原子方式做到这一点吗?这也是个好主意吗?

4

2 回答 2

3

这取决于您要达到的目标。

对于场景 2,大多数时候您想要的是一个计算一次并在以后重用的值。对于这个用例,您可以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 协程,您可能需要检查其他同步原语,例如MutexSemaphore。但总的来说,最好让协程通过通道进行通信,而不是共享可变状态。

于 2022-02-21T17:44:01.583 回答
1

你问什么不是很清楚。但是假设您想确保某些代码仅在第一次执行(或不执行)并且该函数可能被同时调用(因为您要求“原子”),那么答案是:不和不。您的两个代码示例都不是线程安全的,并且可能导致以特殊方式处理的第一次调用不止一次。

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

您可以通过多种方式解决此问题,例如使用互斥锁,但可能最简单和最高效的方法是使用比较和交换操作之一。例如:

val isFirstTime = AtomicBoolean(true)

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

fun onlyForFirstTime(){
  if (isFirstTime.getAndSet(false)) {
    jobDone()
  }
}
于 2022-02-21T19:44:38.630 回答