Kotlin多线程下while循环因变量可见性无法执行的问题
Kotlin多线程线程可见性问题解决方案
你遇到的是典型的线程可见性问题。在JVM内存模型中,每个线程可能会将共享变量的副本缓存到自己的工作内存中,当其他线程修改了主内存中的isReady变量时,主线程的工作内存并不会自动同步这个更新,导致主线程一直读取旧值,陷入死循环。
而println()方法内部包含同步锁操作(比如System.out的打印方法是同步的),执行同步操作时会触发内存屏障,强制线程刷新工作内存,读取主内存中的最新值,所以循环能正常退出。
以下是几种可靠的解决办法:
1. 用@Volatile标记共享变量
在Kotlin中,使用@Volatile注解标记变量,确保变量的读写直接操作主内存,禁止线程缓存副本:
@Volatile private var isReady = false // 其他线程修改isReady thread { // 模拟耗时初始化操作 Thread.sleep(1000) isReady = true } // 主线程等待 while (!isReady) { // 空循环也能正常退出 } println("循环退出,执行后续代码")
2. 使用synchronized同步块
通过同步块强制内存同步,每次循环都获取锁,保证读取的是主内存最新值:
private var isReady = false private val lock = Any() // 其他线程修改变量 thread { Thread.sleep(1000) synchronized(lock) { isReady = true } } // 主线程等待 while (true) { synchronized(lock) { if (isReady) break } } println("循环退出,执行后续代码")
3. 使用标准并发工具类(更推荐)
直接用现成的并发工具替代手动循环,代码更简洁可靠:
用CountDownLatch
val latch = CountDownLatch(1) thread { Thread.sleep(1000) // 完成初始化后触发等待结束 latch.countDown() } // 主线程等待,直到计数归0 latch.await() println("等待完成,执行后续代码")
用CompletableFuture(Kotlin 1.3+支持)
val initFuture = CompletableFuture.runAsync { Thread.sleep(1000) // 执行初始化逻辑 } // 主线程等待任务完成 initFuture.join() println("初始化完成,执行后续代码")
补充:为什么空循环会陷入死循环?
JVM的即时编译器(JIT)会对空循环做优化,它会判定isReady变量没有被当前线程修改,直接将while (!isReady)优化为无限循环,跳过了读取主内存的操作,导致主线程永远看不到其他线程的修改。而println的同步操作会阻止这种优化,同时强制刷新内存。
内容的提问来源于stack exchange,提问作者MoMMde
相关产品推荐
相关产品推荐

