问题描述
我试图通过GUI从用户那里获取一些信息,该GUI在与Kotlin(Jvm)分开的线程中运行。我这样做的尝试是(最小的工作示例,我无法摆脱UI
import java.awt.*
import java.lang.Thread.sleep
import javax.swing.*
val board = Board()
fun main() {
EventQueue.invokelater {
ThreadAnimationEx().isVisible = true
}
var test: String?=null
board.instruction = {
sleep(1000)
test= "test value"
println("Done")
}
while (test == null) {
//uncommenting this line makes this work
// sleep(100)
}
println("Finished with $test")
}
class ThreadAnimationEx() : JFrame() {
init {
add(board)
}
}
class Board : JPanel(),Runnable {
var instruction: (() -> Unit)? = null
private var animator: Thread? = null
override fun addNotify() {
super.addNotify()
animator = Thread(this)
animator!!.start()
}
public override fun paintComponent(g: Graphics) {
super.paintComponent(g)
Toolkit.getDefaultToolkit().sync()
}
override fun run() {
while (true) {
if (instruction != null) {
instruction!!.invoke()
instruction = null
}
sleep(10)
}
}
}
如果未注释sleep(100),则程序可以正常工作,打印
Done
Finished with test value
如果没有这样的片段,我只会得到
Done
这是Kotlin还是jvm中的某些错误?
解决方法
不,这是您程序中的错误。没有任何迹象表明test
的值将会改变,因此JVM完全有权使用寄存器中缓存的值,而不是在执行{{1 }}循环。
您需要在while
变量上使用volatile
修饰符,或者使用专为并发设计的类型,例如AtomicBoolean
。
顺便说一句,对test
的调用得以修复的原因大概是因为发生了一些同步,这导致了内存屏障,从而迫使该值再次从内存中获取。与this question and answer中探讨的打印类似的原因也可以解决这种并发可见性问题。