让我们考虑一下带有协程的简单代码
import kotlinx.coroutines.*
import java.util.concurrent.Executors
fun main() {
runBlocking {
launch (Executors.newFixedThreadPool(10).asCoroutineDispatcher()) {
var x = 0
val threads = mutableSetOf<Thread>()
for (i in 0 until 100000) {
x++
threads.add(Thread.currentThread())
yield()
}
println("Result: $x")
println("Threads: $threads")
}
}
}
Run Code Online (Sandbox Code Playgroud)
据我了解,这是相当合法的协程代码,它实际上产生了预期的结果:
Result: 100000
Threads: [Thread[pool-1-thread-1,5,main], Thread[pool-1-thread-2,5,main], Thread[pool-1-thread-3,5,main], Thread[pool-1-thread-4,5,main], Thread[pool-1-thread-5,5,main], Thread[pool-1-thread-6,5,main], Thread[pool-1-thread-7,5,main], Thread[pool-1-thread-8,5,main], Thread[pool-1-thread-9,5,main], Thread[pool-1-thread-10,5,main]]
Run Code Online (Sandbox Code Playgroud)
问题是是什么使局部变量的这些修改成为线程安全的(或者它是线程安全的?)。我知道这个循环实际上是按顺序执行的,但它可以在每次迭代时更改正在运行的线程。在第一次迭代中线程所做的更改对于在第二次迭代中拾取此循环的线程仍然应该是可见的。哪个代码可以保证这种可见性?我尝试将这段代码反编译为 Java,并使用调试器挖掘协程实现,但没有找到任何线索。