Files
spring-async-demo/virtual-threads-benchmark/docs/01-enabling-virtual-threads.md
T
asmhatre f506b01389 Add virtual-threads-benchmark: re-run Spring Boot 4.1 / JDK 25 benchmarks, JEP 491 pinning fixed
Companion module for the rewritten post 'Virtual Threads on Spring Boot 4.1: The Benchmarks,
Re-Run, and the Pinning Advice That Expired', retitled and re-benchmarked on Boot 4.1.1 /
JDK 25.0.4.1 (the original post was written against Boot 3.4 / JDK 21). Covers: I/O-bound and
CPU-bound throughput (platform vs virtual threads, including a JIT-warmup benchmarking bug this
build caught and fixed), JEP 491 proof that synchronized no longer pins a virtual thread's
carrier across a blocking call as of JDK 24 (obsoleting the old avoid-synchronized advice),
proof that -Djdk.tracePinnedThreads=full is inert on JDK 25, and JEP 506's finalized ScopedValue
API (JDK 25 GA, no --enable-preview, and a different shape than the old preview API). Kept as
its own module rather than a new top-level repository, alongside the existing async/ module,
which already has a stronger dual-JDK JEP 491 proof that this module's docs cross-link to
instead of duplicating.
2026-09-18 08:52:59 +00:00

44 lines
2.4 KiB
Markdown

# 1. Enabling virtual threads on Spring Boot 4.1
[README](../README.md) | Next: [02-benchmark-methodology.md](02-benchmark-methodology.md)
Source: [`application.yml`](../src/main/resources/application.yml), [`DemoController.java`](../src/main/java/com/ankurm/vthreads/DemoController.java).
Test: [`ThreadTypeTest.java`](../src/test/java/com/ankurm/vthreads/ThreadTypeTest.java).
Transcript: [`docs/output/00-thread-type-confirmation.txt`](output/00-thread-type-confirmation.txt).
## Still one property
`spring.threads.virtual.enabled=true` is unchanged since Boot 3.2 and still the whole
configuration surface for most apps on Boot 4.1. It requires JDK 21+; this repo runs it on
JDK 25.
## What actually flips
Confirmed against a real running embedded server, not by reading the reference docs:
```
enabled=false -> Thread: Thread[#9711,http-nio-auto-5-exec-1,5,main] | Virtual: false
enabled=true -> Thread: VirtualThread[#9737,tomcat-handler-0]/runnable@ForkJoinPool-1-worker-2 | Virtual: true
```
The platform-thread name prefix changed between the Boot 3 era and this repo's Boot 4.1 run
(`http-nio-auto-5-exec-1` here vs. the `http-nio-8080-exec-3` shape in the older post) because
this test binds to `server.port=0` (a random port) rather than a fixed 8080 -- Tomcat's
connector-name-derived thread prefix reflects that. Cosmetic, but worth not being surprised by
if your own logs look different from either example.
## Test infrastructure trap worth knowing about
Setting the property via `SpringApplicationBuilder.properties(...)` and expecting it to win
over `application.yml` is a real bug this repo hit while building the benchmark below:
`.properties(...)` binds to Spring's **`defaultProperties`** source, which has the *lowest*
precedence of any property source Spring Boot recognizes -- lower than `application.yml`,
which had `spring.threads.virtual.enabled: false` as its own explicit default. The fix was
passing it as a command-line-style argument to `run(...)` instead
(`"--spring.threads.virtual.enabled=" + value`), which binds at the highest precedence. See
[`LoadBenchmarkTest.java`](../src/test/java/com/ankurm/vthreads/LoadBenchmarkTest.java) for
where this was caught -- the first draft of the CPU-bound benchmark below silently ran both
scenarios on platform threads and reported a difference that didn't exist.
Next: [02-benchmark-methodology.md](02-benchmark-methodology.md).