Share
Embed
Java Concurrency Face-Off: Virtual Threads vs Reactive (ConFoo 2026)
With virtual threads now in Java, is reactive programming still worth it? This talk compares traditional thread pools, Reactive Streams, and virtual threads by building the same app three ways. We’ll examine performance, memory use, debugging, backpressure, and error handling, then wrap up with a clear decision matrix to help you choose the right concurrency model for your needs.
A N M Bazlur Rahman
March 05, 2026
Transcript
26 slides
-
https://bazlur.ca A N M Bazlur Rahman @bazlur_rahman Java Concurrency Face-Off
Virtual Threads vs Reactive -
https://bazlur.ca A N M Bazlur Rahman @bazlur_rahman Our Story Begins
with a Bottleneck 2 • Traditional Java concurrency follows a thread-per-request model. • But threads are expensive, scarce, and mostly wasted due to waiting on I/O. • Threads block on I/O 8090% of the time in typical services -
https://bazlur.ca A N M Bazlur Rahman @bazlur_rahman Two Contenders Emerge
to Solve This Path 1: Reactive Programming 3 Path 2: Virtual Threads “Donʼt block. Ever. Transform everything into streams.ˮ “What if threads were cheap? Like, really cheap?ˮ A small number of event-loop threads handle many connections by never waiting. Work is scheduled as non-blocking callbacks. Write simple, blocking code. The JVM makes it scalable by parking virtual threads instead of blocking OS threads. -
https://bazlur.ca A N M Bazlur Rahman @bazlur_rahman Reactive Code Flows
Like a River Through Pipes What It Looks Like 4 Source filter() map() flatMap() subscribe // Reactive Ingestion Logic public Mono<ProcessingResult> process(Reading reading) { return Mono.zip( repository.save(reading), broadcaster.broadcast(reading), weatherService.fetch(reading.location()) ).flatMap(tuple → { // ... process results from tuple ... }).onErrorResume(ex → { // ... handle error ... }); } Control flow is implicit -
https://bazlur.ca A N M Bazlur Rahman @bazlur_rahman The Reactive Shift:
From Occupying Threads to Handling Events This approach is built on three fundamental ideas: 5 Non-Blocking I/O The Foundation Asynchronous Execution: The Mechanism Event-Driven Model: The Architecture -
https://bazlur.ca A N M Bazlur Rahman @bazlur_rahman Pillar 1 Non-Blocking
IO The thread never blocks waiting for a single connection. It asks the OS for work that is ready “nowˮ and processes it. 6 -
https://bazlur.ca A N M Bazlur Rahman @bazlur_rahman Pillar 2 Asynchronous
Execution 7 Non-Blocking: About not waiting for I/O operations. Asynchronous: About not waiting for a task to complete. -
https://bazlur.ca A N M Bazlur Rahman @bazlur_rahman Pillar 3 The
Event-Driven Model 8 A pipeline that reacts to the flow of data. -
https://bazlur.ca A N M Bazlur Rahman @bazlur_rahman The Reactive Engine:
Putting It All Together 9 -
https://bazlur.ca A N M Bazlur Rahman @bazlur_rahman The Magic: The
Blocking Code That Doesn't Block 11 -
https://bazlur.ca A N M Bazlur Rahman @bazlur_rahman Virtual Threads with
Structured Concurrency // Imperative, sequential code try (var scope = StructuredTaskScope.open()) { scope.fork(() -> repo.save(r)); scope.fork(() -> broadcast(r)); scope.fork(() -> weather(loc)); scope.join(); } 12 -
https://bazlur.ca A N M Bazlur Rahman @bazlur_rahman Two Paths to
Scalability Reactive (WebFlux) Virtual Threads (Loom) 13 • “Donʼt Blockˮ Philosophy • Asynchronous & Non-Blocking • Event-loop based scheduling • Power through Operators • “Blocking is Fineˮ Philosophy • Synchronous code • Lightweight, JVM-managed threads • Simplicity through Imperative Code -
https://bazlur.ca A N M Bazlur Rahman @bazlur_rahman The Arena: A
Fair Fight in the HIVE A thermostat monitoring system that ingests sensor data, enriches it with external weather data, persists it to a database, and streams updates to a live dashboard via Server-Sent Events SSE. The Rules of Engagement • Identical Functionality: Same API surface, same database schema, same business logic. • Equivalent Environments: Deployed in identical containers with the same CPU 4 cores) and memory 2G) limits. • Shared Dependencies: Both use the same PostgreSQL database and simulated external services. 15 -
https://bazlur.ca A N M Bazlur Rahman @bazlur_rahman The Debugging Experience
- Reactive 16 Your applicationʼs story is buried in the frameworkʼs mechanics. -
https://bazlur.ca A N M Bazlur Rahman @bazlur_rahman The Debugging Experience
- Virtual Threads 17 The stack trace reads exactly like your code is written. -
https://bazlur.ca A N M Bazlur Rahman @bazlur_rahman “Observability cost shows
up at 3 AM, not in benchmarks.“ Truth be told… 20 -
https://bazlur.ca A N M Bazlur Rahman @bazlur_rahman Performance + Operability:
What Actually Matters in Production What benchmarks tell us • Average and tail latency (p95 / p99 • Throughput under load • Resource utilization • Error rates What operations demand • Clear causal stack traces • Errors mapped to business flow • Predictable failure boundaries • Fast root-cause analysis under pressure 21 Necessary, measurable, repeatable Inevitable, human, time-critical Numbers describe symptoms. Operability determines how fast you find causes. -
https://bazlur.ca A N M Bazlur Rahman @bazlur_rahman Backpressure: Where Control
Lives 22 Reactive frameworks provide first-class backpressure. Virtual threads require explicit backpressure strategies. -
https://bazlur.ca A N M Bazlur Rahman @bazlur_rahman ? Which model
do you prefer for your next service? Reactive? or Virtual Threads? 23 -
https://bazlur.ca A N M Bazlur Rahman @bazlur_rahman The Right Tool
for the Job Choose Virtual Threads When: • Building typical I/O-bound services REST APIs, CRUD apps). • Prioritizing simple, maintainable code and easy debugging. • Migrating an existing blocking application for better scalability. 24 Consider Reactive When: • Your logic is fundamentally a stream of events (e.g., Kafka processing, UI event handling). • You require fine-grained, built-in backpressure control. • You are working within an existing, mature Reactive ecosystem. -
https://bazlur.ca A N M Bazlur Rahman @bazlur_rahman “The best code
is the code you can understand six months from now at 3 AM during an outage.ˮ — Every On-Call Engineer, Ever Ultimately 25 -
https://bazlur.ca A N M Bazlur Rahman @bazlur_rahman A N M
Bazlur Rahman 26 Java Champion · Sr. Staff Software Engineer · Author of Modern Concurrency in Java · InfoQ Editor https://x.com/bazlur_rahman rokon12 https://www.linkedin.com/in/bazlur/ https://bazlur.ca/ https://bsky.app/profile/bazlur.ca https://www.menti.com/alf6wjhxwf7w