1. Overview

In this quick tutorial, we’re going to see how to control the memory visibility of variables using volatile properties in Kotlin.

First, we’ll introduce volatile properties in Kotlin. Then we’re going to dig deeper and see the internal representation of these properties at the bytecode level.

2. Volatile Properties

Coming from a Java background, one might wonder, what’s the equivalent of Java’s volatile keyword in Kotlin?

To make matters more concrete, let’s walk through this example:

object TaskExecutor : Runnable {

    private var shouldContinue = true

    override fun run() {
        while (shouldContinue) {}
        println("Done")
    }

    fun stop() {
        shouldContinue = false
    }
}

The TaskExecutor singleton object will continue the spin wait as long as the shouldContinue variable is set to true:

fun main() {
    val thread = Thread(TaskExecutor)
    thread.start()

    TaskExecutor.stop()

    thread.join()
}

One might expect that once we call the stop() method, the busy-wait will end immediately and the TaskExecutor will print “Done” to the console.

However, due to the nature of shared multiprocessor architectures and CPU caches, the busy-wait might end with a delay. Adding insult to injury, it might not end at all.

To avoid these sorts of processor or runtime optimizations on the shouldContinue variable, we should annotate that property with a @Volatile annotation:

object TaskExecutor : Runnable {

    @Volatile
    private var shouldContinue = true

    // same as before
}

The @Volatile annotation will mark the JVM backing field of the annotated property as volatile. Thus, the writes to this field are immediately made visible to other threads. Moreover, the reads will always see the latest changes.

Simply put, the @Volatile annotation is the equivalent of Java’s volatile keyword in Kotlin.

3. JVM Representation

Now that we know enough about the Kotlin API for volatile properties, let’s inspect the bytecode.

If we compile the TaskExecutor singleton object with kotlinc:

$ kotlinc TaskExecutor.kt

And then inspect the resulting bytecode with javap:

$ javap -v -p -c TaskExecutor
// omitted for brevity
private static volatile boolean shouldContinue;
    descriptor: Z
    flags: (0x004a) ACC_PRIVATE, ACC_STATIC, ACC_VOLATILE

Then, we’ll see that the shouldContinue field compiled as static value with an ACC_VOLATILE flag, meaning that it’s a volatile property.

4. Conclusion

In this short tutorial, we saw how to control the memory visibility of variables using volatile properties. Moreover, we took a quick peek at the generated bytecode for the @Volatile annotation.

For a more detailed discussion on how volatile properties affect the memory visibility of variables, it’s highly recommended to check out our Guide to the Volatile Keyword in Java.

As usual, all the examples are available over on GitHub.


« 上一篇: Kotlin中的异常处理
» 下一篇: Kotlin中的SAM转换