Skip to content

Java 21 Virtual Threads & Structured Concurrency (JEP 453) demo with Spring Boot 3.2 — parallel API aggregation, timeout, cancellation.

License

Notifications You must be signed in to change notification settings

NullPoint3rDev/virtual-threads

Repository files navigation

Virtual Threads & Structured Concurrency

Java Spring Boot Gradle Docker License: MIT

A Spring Boot 3.2 demo showcasing Java 21 Virtual Threads (Project Loom) and Structured Concurrency (JEP 453).
Parallel API aggregation with timeouts and cancellation — no reactive stack required.

FeaturesQuick StartAPIArchitecture


✨ Features

Feature Description
Virtual threads Tomcat and @Async run on virtual threads (spring.threads.virtual.enabled: true). One request = one lightweight thread; blocking I/O is cheap.
ExecutorService on VTs Parallel calls to two “external” services (stubs) via Executors.newVirtualThreadPerTaskExecutor() with a 2s timeout and cancel-on-timeout.
StructuredTaskScope Same scenario using JEP 453 structured concurrency: one scope, fork + joinUntil, automatic cancellation on failure or timeout.
AsyncConfigurer Custom executor so all @Async methods run on virtual threads.
Docker one-liner docker compose up --build to build and run; no local JDK required.
Tests Unit tests for the service (both code paths); integration tests for the controller.

🏗 Architecture

flowchart LR
    subgraph Client
        C[HTTP Client]
    end
    subgraph "Spring Boot :8080"
        R[Controller]
        R --> E["/api/service\nExecutorService"]
        R --> S["/api/service/structured\nStructuredTaskScope"]
        E --> VT1[Virtual Thread 1]
        E --> VT2[Virtual Thread 2]
        S --> VT3[Virtual Thread 3]
        S --> VT4[Virtual Thread 4]
    end
    VT1 --> A[callServiceA]
    VT2 --> B[callServiceB]
    VT3 --> A
    VT4 --> B
    C --> R
Loading
  • ExecutorService path: Two tasks submitted to a virtual-thread executor; Future.get(2, SECONDS) with cancel on timeout.
  • StructuredTaskScope path: ShutdownOnFailure scope, fork for each call, joinUntil(deadline), then throwIfFailed() and collect results.

🚀 Quick Start

Prerequisites

  • JDK 21 (for local run and tests)
  • Docker and Docker Compose (for containerized run)

Option 1: Run with Docker (recommended)

git clone https://github.com/NullPoint3rDev/virtual-threads.git
cd virtual-threads
docker compose up --build

Port 8081 is used by default to avoid clashes with other apps on 8080. Change docker-compose.yml to "8080:8080" if you prefer.

Option 2: Run locally

./gradlew bootRun

Then open http://localhost:8080/api/service (and /api/service/structured).
StructuredTaskScope is a preview API in Java 21; the build enables --enable-preview for compile and run.


📡 API

Method Path Description
GET /api/service Aggregates two stub calls using ExecutorService (virtual threads).
GET /api/service/structured Same using StructuredTaskScope.ShutdownOnFailure.

Example response:

{"serviceA":"result-A","serviceB":"result-B"}

Health check: GET /actuator/health{"status":"UP"}.


🧪 Tests

./gradlew test
  • VirtualThreadsServiceTest — unit tests for fetchWithVirtualThreads() and fetchWithStructuredConcurrency() with a real virtual-thread executor.
  • VirtualThreadsControllerTest@SpringBootTest + MockMvc for both endpoints.

Preview is enabled for the test JVM via jvmArgs("--enable-preview") in build.gradle.kts.


📦 Stack

Technology Role
Java 21 Virtual threads (JEP 444), StructuredTaskScope (JEP 453, preview).
Spring Boot 3.2 Web, Actuator; native virtual-thread support.
Gradle 8.5 Build; --enable-preview for main, test, and bootRun.
Docker Multi-stage Dockerfile (Eclipse Temurin 21 JDK → JRE); --enable-preview in container entrypoint.

License

MIT

About

Java 21 Virtual Threads & Structured Concurrency (JEP 453) demo with Spring Boot 3.2 — parallel API aggregation, timeout, cancellation.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors