从多个线程对 Kotlin var 进行线程安全访问

Bas*_*ass 4 concurrency multithreading kotlin safe-publication kotlin-coroutines

考虑以下 Kotlin 代码:

import kotlin.concurrent.thread

fun main() {
    println("Press <Enter> to terminate.")

    var interrupted = false

    val worker = thread {
        while (!interrupted) {
            println("Working...")
            Thread.sleep(1000L)
        }
    }

    System.`in`.read()

    println("Terminating...")
    interrupted = true

    worker.join()

    println("Terminated.")
}
Run Code Online (Sandbox Code Playgroud)

以及使用协程重写的相同示例:

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

fun main() = runBlocking {
    println("Press <Enter> to terminate.")

    var interrupted = false

    val worker = launch(Dispatchers.IO) {
        while (!interrupted) {
            println("Working...")
            delay(1000L)
        }
    }

    System.`in`.read()

    println("Terminating...")
    interrupted = true

    worker.join()

    println("Terminated.")
}
Run Code Online (Sandbox Code Playgroud)

这两个示例在大多数情况下都可以工作,但都被破坏了,因为在字节码级别,boolean从多个线程访问的变量被表示kotlin.jvm.internal.Ref.BooleanRef为非线程安全的。

值得一提的是,Java 编译器需要interrupted这样final,而相同的 Java 代码将根本无法编译。

问题

  1. java.util.concurrent.atomic.AtomicBoolean仅使用标准库(即 w/o或)重写上述代码的规范方法是什么kotlinx.atomicfu.AtomicBoolean
  2. 如何以最可移植的方式重写上面的代码(使用协程的第二个片段),以便它可以针对Kotlin/Multiplatform

小智 8

基于Kotlin 文档

\n

第一个解决方案是线程安全的数据结构,例如AtmoicBoolean

\n
import java.util.concurrent.atomic.AtomicBoolean\nimport kotlin.concurrent.thread\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.delay\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.runBlocking\n\nfun main() {\n    println("Press <Enter> to terminate.")\n    val interrupted = AtomicBoolean()\n    val worker = thread {\n        while (!interrupted.get()) {\n            println("Working...")\n            Thread.sleep(1000L)\n        }\n    }\n\n    System.`in`.read()\n    println("Terminating...")\n    interrupted.set(true)\n    worker.join()\n    println("Terminated.")\n}\n\n// coroutine way\nfun main_2() = runBlocking {\n    println("Press <Enter> to terminate.")\n    val interrupted = AtomicBoolean()\n    val worker = launch(Dispatchers.IO) {\n        while (!interrupted.get()) {\n            println("Working...")\n            delay(1000L)\n        }\n    }\n\n    System.`in`.read()\n    println("Terminating...")\n    interrupted.set(true)\n    worker.join()\n    println("Terminated.")\n}\n
Run Code Online (Sandbox Code Playgroud)\n

第二种解决方案是互斥

\n
import kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.delay\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.runBlocking\nimport kotlinx.coroutines.sync.Mutex\nimport kotlinx.coroutines.sync.withLock\n\nval mutex = Mutex()\n\nfun main() = runBlocking {\n    println("Press <Enter> to terminate.")\n    var interrupted = false\n    val worker = launch(Dispatchers.IO) {\n        while (mutex.withLock { !interrupted }) {\n            println("Working...")\n            delay(1000L)\n        }\n    }\n\n    System.`in`.read()\n    println("Terminating...")\n    mutex.withLock { interrupted = true }\n    worker.join()\n    println("Terminated.")\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我只是使用两个解决方案来解决这个问题,在这里你可以找到另一个解决方案\n

\n
\n

如何以最可移植的方式重写上面的代码(第二个片段,使用协程),以便它可以针对 Kotlin/Multiplatform?

\n
\n
\n我在 kotlin-multiplatform 方面没有太多经验,但是你不能在 Kotlin 多平台中使用`Dispacher.IO`,因为它绑定到 JVM,所以如果你\xe2\x80\x99re \n使用 Kotlin/JavaScript 或 Kotlin/Native 项目,\xe2\x80\x99 无法使用它。\n