You may have heard it a million times that Kotlin coroutines are lightweight compared to java threads. But why exactly is it? Let’s understand it.
What exactly is a thread?
A thread is a single sequential flow of execution of tasks of a process in an operating system (OS).
OS threads are at the core of Java’s concurrency model. Java threads are just a wrapper at OS thread.
There is a one-to-one correspondence between Java threads and system kernel threads, and the thread scheduler of the system kernel is responsible for scheduling Java threads.
When you create a new Java thread, the JVM must work with the underlying OS to create and manage that thread, which is quite expensive because the JVM must communicate with the OS back and forth throughout the thread’s lifetime.
This switching is an expensive operation, which makes threads expensive, and you can’t launch a large number of threads (e.g., 10,000) at once.
However, because Kotlin coroutines are entirely managed by the language (and ultimately by the programmer), they do not require communication with the underlying OS to be created and managed. This eliminates the need to work with the operating system. This is why coroutines are lightweight and can be launched millions at once.
Fun fact
To avoid this three-decade-long pain, Java 19 introduced the concept of virtual threads. Virtual threads are lightweight threads that are managed by the JVM rather than the OS. Java 19 includes it as a preview feature. You can start a virtual thread as shown below.
Thread.startVirtualThread(() -> {
System.out.println("Hello, Project Loom!");
});