【问题标题】:How does synchronization happens under the hood in Kotlin Coroutine?在 Kotlin Coroutine 的底层,同步是如何发生的?
【发布时间】:2020-08-22 00:27:13
【问题描述】:

我试图了解协程如何访问其他线程的数据。看看下面的 kotlin 程序,我试图理解主线程中的 variableAccessCount 可以从 Coroutine C1 和 Coroutine C2 访问,但是根据我的理解,协程是在不同线程上运行的一段代码,并且在 Android 线程中可以'不被直接触及,有机制可以做到这一点,例如 Handler,在协程中我们也确实有 withContext() 但特定于这个例子,

import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.coroutines.coroutineContext

var variableAccessCount = 0

fun main() {
    println("${Thread.currentThread()}")

    GlobalScope.launch {//Coroutine C1
        println("${Thread.currentThread()}")
        firstAccess() }

    GlobalScope.launch {//Coroutine C2
        println("${Thread.currentThread()}")
        secondAcess() }

    Thread.sleep(2000L)

    print("The variable is accessed $variableAccessCount number of times")
}

suspend fun firstAccess() {
    delay(500L)
    variableAccessCount++
}

suspend fun secondAcess() {
    delay(1000L)
    variableAccessCount++
}

有人能帮我理解变量 var functionCalls = 0 的内部同步是如何发生的吗?这个变量在主线程中声明,可以从两个挂起函数(completeMessage 和改进消息)访问,它们在协程内部但在不同的工作线程上运行。

程序 O/P

Thread[main,5,main]
Thread[DefaultDispatcher-worker-3,5,main]
Thread[DefaultDispatcher-worker-2,5,main]
The variable is accessed 2 number of times

【问题讨论】:

  • 它没有。您应该使用AtomicIntegerLongAdder
  • 它正在执行,请从上面的代码中尝试
  • 是的,它有效。但这并不能保证,您将自己暴露在竞争条件下。请参阅Why is i++ not atomic? 的此答案。您所说的“同步”通常称为“原子性”,由我上面提到的类处理。线程也可能有单独的执行,但它们仍然共享内存。
  • 了解,但关于您上面的评论,在 Android 中,UI 无法从另一个线程触摸 UI 线程
  • 不能,但这是 Android 框架的限制,而不是 JVM(或 Kotlin)。

标签: android multithreading kotlin kotlin-coroutines


【解决方案1】:
  • 使用AtomicInteger:
val variableAccessCount = AtomicInteger(0)

suspend fun firstAccess() {
    delay(500L)
    variableAccessCount.incrementAndGet()
}

suspend fun secondAcess() {
    delay(1000L)
    variableAccessCount.incrementAndGet()
}
  • 细粒度的线程限制
val counterContext = newSingleThreadContext("CounterContext")
var variableAccessCount = 0

suspend fun firstAccess() {
    delay(500L)
    withContext(counterContext) { variableAccessCount++ }
}

suspend fun secondAcess() {
    delay(1000L)
    withContext(counterContext) { variableAccessCount++ }
}
  • 互斥
val mutex = Mutex()
var variableAccessCount = 0

suspend fun firstAccess() {
    delay(500L)
    mutex.withLock  { variableAccessCount++ }
}

suspend fun secondAcess() {
    delay(1000L)
    mutex.withLock  { variableAccessCount++ }
}

【讨论】:

    猜你喜欢
    • 2020-02-19
    • 2020-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-23
    • 2020-05-06
    • 2020-07-29
    • 2020-11-30
    相关资源
    最近更新 更多