Consider the following Kotlin code:
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.")
}
as well the same example rewritten using coroutines:
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.")
}
Both examples will work in most cases, and yet both are broken, because, at the bytecode level, a boolean
variable accessed from more than a single thread is represented as a kotlin.jvm.internal.Ref.BooleanRef
which is not thread-safe.
It's worth mentioning that a Java compiler will require interrupted
to be final
and the identical Java code will simply fail to compile.
Questions
- What is the canonical way to rewrite the above code using just the standard library (i. e. w/o
java.util.concurrent.atomic.AtomicBoolean
orkotlinx.atomicfu.AtomicBoolean
)? - How can the above code (the 2nd fragment which uses coroutines) be rewritten in the most portable way, so that it can target Kotlin/Multiplatform?