0

I was trying to get some info from user with GUI that runs in separate thread with Kotlin(Jvm). My attempt at doing this was ( minimal working example, I was not able to get rid of 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)
        }
    }
}

If the sleep(100) is not commented out then the program works correctly, prints

Done
Finished with test value

If there is no such fragment then I only get

Done

Is this some bug in kotlin or jvm?

1 Answers1

2

No, it's a bug in your program. There is nothing to indicate that the value of test will change, so the JVM is perfectly entitled to use a value cached in a register rather than fetching the value from memory when performing the test of the condition in the while loop.

You need to either use the volatile modifier on the test variable or use a type designed for concurrency such as AtomicBoolean.

By the way, the reason that the call to sleep fixes it is presumably because there is some synchronization happening that causes a memory barrier which forces the value to be fetched again from memory. It is similar to why printing can also fix such a concurrency visibility problem, as explored in this question and answer.

David Conrad
  • 15,432
  • 2
  • 42
  • 54