You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 04:35:26