Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java virtual threads vs Kotlin coroutines

How do Java 21 virtual threads compare to Kotlin coroutines?

When coding in Kotlin, is it better to prefer one over the other?

This video: Java 21 new feature: Virtual Threads #RoadTo21 seems to frown upon using virtual threads for non-IO or non-blocking tasks.

I create coroutines right and left even for CPU-intensive tasks in my Kotlin code. Is this not alright anymore?

like image 451
Mahozad Avatar asked Aug 31 '25 21:08

Mahozad


2 Answers

Is this not alright anymore? It is alright, Java virtual threads won't replace Kotlin coroutines.

There is a presentation by Roman Elizarov that covers the difference.

Short Recap from presentation

Virtual Threads (Project Loom) are good for

  • Virtual Thread per request
  • Updating existing code

Kotlin Coroutines are good for

  • Highly-concurrent code
  • Event-based systems
  • Structured concurrency and cancellations

And, as mentioned by @Slaw in the comment, coroutines can be executed on virtual threads too. Also coroutines can be used with Kotlin/JS and Kotlin/Native.

like image 76
Kiryl Tkach Avatar answered Sep 03 '25 09:09

Kiryl Tkach


From this video, we can say that Loom is great. But it's not a replacement for Kotlin coroutines. Coroutines are still the recommended thing to use when dealing with concurrent processes in Kotlin. To compare them,

  • Loom can improve the performance of applications: it can run multiple virtual threads and it costs less to have blocked virtual threads than to have regular threads blocked.
  • Kotlin coroutines are intrusive because we cannot call suspend functions in normal function, which is not the case of Loom
  • Structured concurrency is much easier with Kotlin coroutines than Loom.
  • Interoperability between Kotlin coroutines and reactive programming is simpler as we can just use flows than the one between loom and reactive programming.

To wrap up, we can say that the best thing Loom has to propose is the virtual threads which can improve performance, while Kotlin coroutines have more to offer. Why not use both of the features together?

Well, there is a concept introduced by Moskala in his "Kotlin Coroutines: Deep Dive" book which is interesting. We can use Loom directly in Kotlin Coroutines code and have better performance while keeping structured concurrency and all the cool stuff we get in Coroutines. To do that, we use virtual threads to replace Dispatchers.IO. Below is an example of code that uses a virtual thread.

val LoomDispatcher = Executors
  .newVirtualThreadPerTaskExecutor()
  .asCoroutineDispatcher()
val Dispatchers.Loom: CoroutineDispatcher
  get() = LoomDispatcher

suspend fun main() = measureTimeMillis {
  coroutineScope {
    repeat(100_000) {
      launch(Dispatchers.Loom) {
        Thread.sleep(1000)
      }
    }
  }
}.let(::println)

Because Dispatchers.IO has just 64 threads, the code above will take over 26 minutes, but we can make use of limitedParallelism to increase the number of threads and get the chance to execute the code quickly. The code using Dispatchers.IO is as follows:

suspend fun main() = measureTimeMillis {
  val dispatcher = Dispatchers.IO
    .limitedParallelism(100_000)
  coroutineScope {
    repeat(100_000) {
      launch(dispatcher) {
        Thread.sleep(1000)
      }
    }
  }
}.let(::println)

I didn't personally run the code with virtual threads but it's said in the book that it took a bit more than two seconds to execute (This is amazing knowing that we block each of the 100,000 threads for 1 second), but the second code took around 30s to finish executing.

I would say the best way to make the code performant and use some cool stuff that Coroutines offers, we can use Loom as a substitution for Dispatchers.IO but keep using Coroutines, though there are no any kinds of recommendations in the documentation.

like image 32
kamdaou Avatar answered Sep 03 '25 10:09

kamdaou