Kotlin coroutines and JavaFX threads
Tags: kotlin, javafx, coroutines, threads
Published: 2019-09-30 05:51:41

---
title: Kotlin coroutines and JavaFX threads
published: true
tags: kotlin, javafx, coroutines, threads
canonical_url: 
---

On October 29, 2018 JetBrains released a [new version of Kotlin (1.3)](https://blog.jetbrains.com/kotlin/2018/10/kotlin-1-3/) that included a long-awaited feature of the language: coroutines. Contrary to Go’s `goroutine` construct, they are not implemented as a language feature. Instead they are developed as a pure library implementation written in Kotlin. But apart from that they share a lot of similiarites with goroutines.

Behind the scenes, coroutines are very lightweight because they are being multiplexed on a few threads and creating one is much faster than spawning a new thread.

You can learn more about them over at JetBrains’ tutorial: [“Your first coroutine with Kotlin”](https://kotlinlang.org/docs/tutorials/coroutines/coroutines-basic-jvm.html). Here I want to show you the caveat that you might encounter in a JavaFX applications when using coroutines.

So this is my basic JavaFX application written in Kotlin:

```kotlin
class MyApp : Application() {
    private val button = Label().also { it.text = "waiting for 0s" }

    override fun start(primaryStage: Stage?) {
        val pane = Pane().also {
            it.children.add(button)
        }

        primaryStage?.scene = Scene(pane,200.0,200.0)
        primaryStage?.show()
    }
}

fun main() {
    launch(MyApp::class.java)
}
```

Nothing special here, just a GUI with a label that shows the text `waiting for 0s`. Now we want to extend our application to continuously update the label to always tell me the exact time I waited.

```kotlin
class MillisElapsedCounter(private val observer: Observer) {
    fun start() {
        GlobalScope.launch(Dispatchers.Default) {
            var millisElapsed = 0

            while (true) {
                delay(1000)
                millisElapsed += 1000
                observer.notify(millisElapsed)
            }
        }
    }

    interface Observer {
        fun notify(millisElapsed: Int)
    }
}
```

**Notice that you need to add a dependency to `org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1` to be able to run this (remember: it’s just a library!)**

So this is the implemention of the `MillisElapsedCounter` class and a corresponding `Observer` that is being notified every 1000ms. Clients of this class have to instantiate it providing an observer. Calling `start()` will then launch a new coroutine using the default dispatcher (there is a pool of dispatchers - which are threads behind the scenes - you can use) and return immediately. Note that `delay(1000)` is a `suspend` function, it will suspend execution in the thread it runs in. Running that in the application thread would freeze the UI forever and would be a bad idea.

To use the counter we also need to update `MyApp` to implement `MillisElapsedCounter.Observer`’s `notify(millisElapsed: Int)` and start the counter like this:

```kotlin
class MyApp : Application(), MillisElapsedCounter.Observer {
    private val button = Label().also { it.text = "waiting for 0s" }

    override fun start(primaryStage: Stage?) {
        MillisElapsedCounter(this).start()
        ...
    }

    override fun notify(millisElapsed: Int) {
        button.text = "waiting for ${millisElapsed / 1000}s"
    }
}
```

Now if you run that, it will throw a `java.lang.IllegalStateException` exception that is coming from JavaFX:

> Exception in thread “DefaultDispatcher-worker-3” java.lang.IllegalStateException: Not on FX application thread; currentThread = DefaultDispatcher-worker-3

To prevent from concurrency issues in the state of the UI, JavaFX prevents other threads from changing it. Look at the `main()` function that uses `launch(MyApp::class.java)` to start the application. This starts a new thread called `JavaFX-Launcher` which in turn starts the `JavaFX Application Thread` which runs all the UI related stuff. This one is the only thread allowed to make changes in the UI at runtime.

This means that we need to execute the changes that are being made to `button.text` in this very thread. The Kotlin team implemented another library for this sole purpose: **org.jetbrains.kotlinx:kotlinx-coroutines-javafx:1.1.1** provides a new Dispatcher `Dispatchers.JavaFx` that uses the JavaFX Application Thread (there’s also **-android** and **-swing** to be used correspondingly).

Then the solution to our problem here is to use the correct Dispatcher `Dispatchers.JavaFx` and to implement another interface in `MyApp` called `CoroutineScope`:

```kotlin
class MyApp : Application(), MillisElapsedCounter.Observer, CoroutineScope {
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.JavaFx
        ...
```

As it is now a `CoroutineScope` we can launch new coroutines directly from `notify()` using the correct scope:

```kotlin
override fun notify(millisElapsed: Int) {
    launch {
        button.text = "waiting for ${millisElapsed / 1000}s"
    }
}
```

And that’s it! The exception will no longer occur and everything will run as expected - I waited a long time, and it still counts happily the seconds I waited :)

One thing we can improve though is that `MillisElapsedCounter` runs a coroutine in the `GlobalScope` which means that you need to keep track of it’s lifetime (if you were interested in that - eg. stopping it). More details on that in [The reason to avoid GlobalScope](https://medium.com/@elizarov/the-reason-to-avoid-globalscope-835337445abc). To fix that we could implement the interface `CoroutineScope` in `MillisElapsedCounter` as well:

```kotlin
class MillisElapsedCounter(private val observer: Observer) : CoroutineScope {
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Default

    fun start() {
        launch { ... }
    }
    ...
```

We now have two coroutines cleanly separated from each other and each running in it’s own scope. A clean and simple solution I think.

The complete source code is available on GitHub, so you can clone it and play around with it:

{% github domnikl/kotlin-coroutines-and-javafx-threads %}

You can read more about that in [Guide to UI programming with coroutines](https://github.com/Kotlin/kotlinx.coroutines/blob/master/ui/coroutines-guide-ui.md#launch-ui-coroutine).