Tag: concurrency

  • Kotlin coroutines vs Java virtual threads: a practical comparison

    Both Kotlin coroutines and Java virtual threads (Project Loom) let you write concurrent code that reads like sequential code. But they solve the problem at different layers of the stack.

    The problem they both solve

    Classic platform threads are expensive. They carry a 1:1 mapping to OS threads, which means high memory overhead (~1 MB per thread) and slow context switching. If you have 10,000 concurrent HTTP connections, you’re in trouble.

    Virtual threads (Project Loom)

    // Just use ExecutorService with virtual threads
    try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
        executor.submit(() -> {
            var result = httpClient.send(request, BodyHandlers.ofString());
            System.out.println(result.body());
        });
    }

    Virtual threads are cheap JVM threads managed by the runtime. When a virtual thread blocks on I/O, the JVM parks it and runs another one. Your existing blocking code works as-is — no async/await, no callback hell.

    Kotlin coroutines

    // Structured concurrency with coroutines
    suspend fun fetchData(): String = withContext(Dispatchers.IO) {
        httpClient.get(url).body()
    }
    
    runBlocking {
        val result = fetchData()
        println(result)
    }

    Coroutines are a language feature. They compile suspend functions into state machines and schedule them on a thread pool. You get fine-grained control over dispatchers, structured concurrency, and first-class cancellation.

    So which should you use?

    • On Java 21+ with blocking I/O? Virtual threads are a drop-in win with zero code changes.
    • Building a Kotlin app from scratch? Coroutines give you a richer concurrency model.
    • Need structured cancellation, flow, or reactive pipelines? Coroutines win easily.
    • Maintaining legacy Java code? Virtual threads are far less invasive.

    They’re not really competing. In a Kotlin app targeting Java 21, you can run coroutines on virtual threads by setting Dispatchers.IO to use them.

vanderzee.org

Software Engineer & Maker — Java · Kotlin · Embedded Systems


© 2026 vanderzee.org