Backend Development 24 min read

Understanding Java Virtual Threads: From Traditional Thread Models to Stackful Coroutines

The article traces Java’s concurrency evolution from heavyweight thread‑per‑request and complex reactive models to JDK 21’s virtual threads, which act as stack‑ful coroutines offering lightweight, heap‑allocated threads, full stack traces, and blocking‑I/O compatibility while preserving the familiar thread API.

DaTaobao Tech
DaTaobao Tech
DaTaobao Tech
Understanding Java Virtual Threads: From Traditional Thread Models to Stackful Coroutines

This article examines the evolution of Java's concurrency model, starting from the classic "thread‑per‑request" model, moving through asynchronous/reactive programming, and finally introducing virtual threads as a stackful coroutine implementation in JDK 21.

In the traditional servlet ecosystem each request is handled by a dedicated OS thread, which leads to high memory consumption (e.g., a 1 MB stack per thread) and costly context switches. The article contrasts this with asynchronous/reactive models that avoid blocking kernel threads by using event‑loop mechanisms, but notes drawbacks such as complex callback chains and loss of thread‑local context.

The concepts of stackless (e.g., Kotlin) and stackful (e.g., Go) coroutines are explained. Stackless coroutines are implemented as state machines without a dedicated call stack, while stackful coroutines maintain an independent stack for each coroutine, enabling full stack traces and easier debugging.

Example of a stackless coroutine in Kotlin:

package org.example

import kotlinx.coroutines.*

suspend fun requestToken(): String {
    println("当前requestToken执行线程为:${Thread.currentThread()}")
    delay(1000) // simulate blocking
    return "token"
}

suspend fun fetchData(token: String): String {
    println("当前fetchData执行线程为:${Thread.currentThread()}")
    delay(1000)
    return "$token:success"
}

fun main() = runBlocking {
    launch {
        val token = requestToken()
        val result = fetchData(token)
        println(result)
    }
    println("当前main执行线程为:${Thread.currentThread()}")
    delay(5000)
}

The same logic rewritten with explicit callbacks shows how the suspend keyword is essentially syntactic sugar for a CPS transformation.

Example of a stackful coroutine in Go (goroutine):

package main

import (
    "fmt"
    "time"
)

func requestToken(tokenCh chan<- string) {
    fmt.Println("requestToken")
    time.Sleep(2 * time.Second)
    tokenCh <- "token"
}

func fetchData(tokenCh <-chan string) {
    token := <-tokenCh
    fmt.Println("fetchData")
    time.Sleep(2 * time.Second)
    fmt.Printf("%s:success\n", token)
}

func main() {
    tokenCh := make(chan string)
    go requestToken(tokenCh)
    go fetchData(tokenCh)
    fmt.Println("主线程其他逻辑")
    time.Sleep(5 * time.Second)
}

Java virtual threads combine the advantages of stackful coroutines with the familiar thread API. They are lightweight, heap‑allocated user threads (n:m scheduling) that can block on I/O without blocking the carrier OS thread. Sample usage:

Thread.startVirtualThread(() -> {
    System.out.println("hello virtual thread");
});

ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
executor.submit(() -> {
    // business logic
    System.out.println("task in virtual thread");
});

Key characteristics of virtual threads include cheap creation/destruction, compatibility with existing thread‑local APIs, and the ability to run blocking I/O transparently. However, they can be "pinned" to a carrier thread in certain scenarios (critical sections, native calls, synchronized blocks), which may lead to resource waste. JEP 491 aims to eliminate pinning issues in a future JDK release.

In summary, virtual threads provide a stackful coroutine model that preserves the simplicity of synchronous code while delivering the scalability needed for high‑concurrency Java applications.

JavaconcurrencyVirtual ThreadsAsync ProgrammingcoroutinesJDK21
DaTaobao Tech
Written by

DaTaobao Tech

Official account of DaTaobao Technology

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.