# Using Kotlin Coroutines

### Overview

* With the advent of `Virtual Thread` in **Java 19**, synchronous programming continues to dominate programming paradigms with its readability as a weapon. Meanwhile, **Kotlin** offers its own unique approach to asynchronous programming with **Coroutines**, which has many strengths in solving bottlenecks and parallel processing. The first impression of coroutines was not that of a completely newly invented secret weapon, but rather it made using threads really easy. It even felt liberating from the conscious callbacks hell. This article summarizes the basic usage of **Kotlin** coroutines from a server-side perspective using **Kotlin/JVM** and will be updated continuously.
    

### build.gradle.kts

* Add the following content to the **build.gradle.kts** at the project root.
    

```kotlin
val kotlinCoroutinesVersion by extra { "1.8.0" }

dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinVersion")
    runtimeOnly("org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:$kotlinVersion")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:$kotlinVersion")
}
```

### Switching CoroutineDispatcher to Virtual Thread

* **Kotlin** has long provided developers with a similar suspend function through coroutines, even before the advent of Virtual Threads. By writing the code below and using `Dispatchers.LOOM`, which applies virtual threads instead of the traditionally used [`Dispatchers.IO`](http://Dispatchers.IO), coroutines can be executed on virtual threads.
    

```kotlin
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asCoroutineDispatcher
import java.util.concurrent.Executors

val Dispatchers.LOOM: CoroutineDispatcher
    get() = Executors.newVirtualThreadPerTaskExecutor().asCoroutineDispatcher()
```

### runBlocking

* The start of a coroutine is the creation of a `runBlocking` block. It acts as the first gateway to create coroutine blocks on the current thread.
    

```kotlin
fun main() {

    // [1] Transition to a state where coroutines can be executed on the current thread
    runBlocking {

        // Still using the current thread within the block
        // [2] Writing 0 or more coroutine blocks
    }

    // [3] Resuming the current thread after all the logic inside the runBlocking coroutine block has finished
}
```

* Or, it can be used directly as a block for a specific function.
    

```kotlin
fun doSomeCoroutine() = runBlocking {

    // Writing 0 or more coroutine blocks
}
```

* In the **runBlocking** block, the current thread continues as it is. It's important to know that even if any coroutine execution within the **runBlocking** block runs in parallel or asynchronously, the **runBlocking** block does not conclude until those blocks are completely finished.
    
* From the example above, the **runBlocking** block might seem insignificant, but only within this block can `coroutineScope`, `launch`, `async`, and other coroutine blocks be written. More on this below.
    

### launch

```kotlin
runBlocking {

    // [1] Writing a coroutine block that uses the current thread
    launch {
        // Write execution logic
    }

    // [2] Writing a coroutine block using a new thread optimized for IO requests
    launch(Dispatchers.LOOM) {
        // Executed on a thread named DefaultDispatcher-worker-{thread-number}
        // Write execution logic
    }

    // [3] Writing a coroutine block using a new thread optimized for CPU operations
    launch(Dispatchers.Default) {
        // Executed on a thread named DefaultDispatcher-worker-{thread-number}
        // Write execution logic
    }

    // [4] If applied, specific logic can be executed in parallel on different threads
    (1..1000).forEach {
        launch(Dispatchers.LOOM) {
            // Executed on a thread named DefaultDispatcher-worker-{thread-number}
            doSomething(it)
        }
    }

    // [5] The execution order of each launch block is determined randomly
}
```

### suspend

* `suspend` is the true star that shines in coroutines and the reason for writing this article. By simply adding the `suspend` keyword in front of a regular function, it can be executed without pausing the current thread. This revolutionary method allows multiple threads to handle the execution based on the system's conditions without requiring special attention from developers.
    

```kotlin
// Add the suspend keyword in front of fun
suspend fun doSomething(number: Int): String {

    // [1] Logic 1
    // [2] IO logic 2 taking 100ms, at this point, other suspend functions can take over the idle current thread.
    // [3] Logic 3, likely to be executed by a different thread.

    return "something"
}

// To preserve the caller thread's MDC fields, add withContext(MDCContext())
suspend fun doSomething(number: Int): String = withContext(MDCContext()) {
    ...
    return@withContext "foobar"
}
```

* It's crucial to understand that `suspend` does not speed up the execution of the function itself. The execution of the function is no different from any regular function. However, the true strength of `suspend` lies in its use during operations that block threads, such as remote database queries. In such cases, a regular function would block the current thread until the operation is completed, essentially creating idle threads in the system temporarily. In contrast, a `suspend` function, when the thread becomes idle, immediately reassigns the thread to other tasks by the **Dispatcher**. So, while the execution speed of the function remains unchanged, it allows threads to be lent to other important functions that need to be executed simultaneously. Consequently, using `suspend` functions extensively can significantly enhance the overall performance of the system.
    
* For `suspend` to be executed by multiple threads as intended, a **Dispatcher** must be declared in the parent coroutine block as follows.
    

```kotlin
// The current thread works solely for doSomething().
runBlocking {
    doSomething(100)
}

// Multiple IO threads work for doSomething().
runBlocking(Dispatchers.LOOM) {
    doSomething(100)
}

// Multiple Default threads work for doSomething().
runBlocking(Dispatchers.Default) {
    doSomething(100)
}
```

### Calling suspend functions in Spring MVC

* The best environment to use coroutines is within **Spring WebFlux**. However, it's not impossible in **Spring MVC**, and suspend functions can be called as follows.
    

```kotlin
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.slf4j.MDCContext
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController

@RestController
class FooController(
    private val fooService: FooService
) {
    @GetMapping("/foos")
    fun getFoo(): ResponseEntity<Foo> {

        return runBlocking(Dispatchers.LOOM + MDCContext()) {
            // Call the suspend function FooService#getFoo(), a @Service spring bean
            val result = async { fooService.getFoo({id}) }
            ResponseEntity.ok(result.await())
        }
    }
}
```

### Calling suspend functions in @Scheduled

* Below is an example of calling a suspend function in a **@Scheduled** logic.
    

```kotlin
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.slf4j.MDCContext
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock
import org.springframework.context.annotation.Profile
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Component

@Profile("batch")
@Component
class BatchScheduledService(
    private val fooService: FooService
) {
    @Scheduled(cron = "0 0 * * * *")
    @SchedulerLock(name = "batchUpdateFoos", lockAtLeastFor = "30s", lockAtMostFor = "1h")
    fun batchUpdateFoos() {

        runBlocking(Dispatchers.LOOM + MDCContext()) {

            val result = async { fooService.getFoo({id}) }
            result.await()
        }
    }
}
```

### References

* [Kotlin Coroutines dispatchers](https://kt.academy/article/cc-dispatchers)
    
* [StackOverflow - Is it better to use a thread or coroutine in Kotlin?](https://stackoverflow.com/a/58255417/17742933)
    
* [StackOverflow - What does the suspend function mean in a Kotlin Coroutine?](https://stackoverflow.com/a/54561432/17742933)
    
* [StackOverflow - How important is it to specify dispatchers/context in Kotlin coroutines? What happens if you don’t specify them?](https://stackoverflow.com/a/69853768/17742933)
    
* [StackOverflow - Kotlin Coroutines vs CompletableFuture](https://stackoverflow.com/a/58477365/17742933)
    
* [Andrey Minogin - Kotlin coroutines real life example](https://medium.com/@minogin/kotlin-coroutines-real-life-example-d940cc170217)
    
* [Kotlin coroutines vs RxJava: an initial performance test](https://proandroiddev.com/kotlin-coroutines-vs-rxjava-an-initial-performance-test-68160cfc6723)
    
* [Custom Kotlin Coroutine Context Uses Cases](https://codingwithmohit.com/coroutines/custom-coroutine-context-uses-cases/)
