空的问题,添加一些随机打印修复错误

问题描述

我试图通过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中探讨的打印类似的原因也可以解决这种并发可见性问题。