
Master virtual threads and Java concurrency for high-scale Spring Boot web apps, exploring when they help and practicing with executor services, CompletableFuture, structured concurrency, and Jmeter performance testing.
Examine how the operating system schedules processes and threads and how Java threads wrap OS threads to execute code, and how virtual threads address blocking in microservices.
Set up a Java project called virtual thread playground with Maven and JDK 25 to explore how virtual threads work, using IntelliJ, logback dependency, and enable preview in the pom.
Demonstrate platform thread creation limits with IO intensive tasks, show out of memory or resource limits when scaling, and motivate virtual threads for scalable concurrency.
Explore Java's thread factory methods, including platform thread builder, customizing names and stack size, and using daemon threads with a countdown latch to wait for tasks to finish.
Explore virtual threads in Java through demos that compare platform and virtual threads, show creation via a thread builder, and demonstrate daemon behavior and scaling up to millions of threads.
Virtual threads are lightweight heap objects scheduled by a forkjoinpool. They look like threads but the OS cannot see them, enabling mounting and parking of tasks for non-blocking I/O.
Demonstrate how virtual threads run under carrier threads, showing thread info, parking and unparking, and how a ForkJoinPool worker thread executes virtual tasks, sometimes switching workers.
Explain how virtual threads use a resizable stack chunk stored on the heap, unlike fixed platform thread stacks, and how parking and unparking preserve context during blocking calls.
Explore how stack traces reveal the flow of execution in a multi-method task. Compare platform and virtual threads and practice debugging exceptions from chained calls.
Explore how platform threads and virtual threads handle a CPU intensive task by executing a recursive Fibonacci workload with no I/O, using a timer to compare execution times and behavior.
In this demo, a cpu-intensive fibonacci(45) runs on 1, 5, 10, 20, and 30 platform threads to show how available processors and scheduler behavior affect parallel cpu time.
A cpu intensive task demo shows virtual threads do not outperform platform threads for cpu-bound work; total times are similar, with benefits coming in microservices with many network calls.
Learn how platform threads are scheduled by the OS and virtual threads by the JVM. Explore how the Forkjoinpool uses available processors to match parallelism with the core pool size.
Compare preemptive scheduling by the OS scheduler for platform threads with cooperative scheduling used by virtual threads, and see how CPU time, thread priority, and context switching drive execution.
Explore cooperative scheduling with Java virtual threads through a hands-on demo that shows yield between worker threads and how scheduler parallelism affects execution.
Explore how virtual threads let you write synchronous blocking style code to process orders with product, payment, and shipping services, while the JVM handles non-blocking IO behind the scenes.
Explore synchronization in Java virtual threads, addressing race conditions and data corruption when shared objects are accessed concurrently. Learn how synchronization controls access to critical sections to preserve thread safety.
Explore a race condition in a multi-threaded compute task using ArrayList, then implement synchronization or a thread-safe list to achieve deterministic 10,000 results with platform and virtual threads.
Reveal how thread pinning in java 21–23 blocked virtual threads on synchronized code like updating shared document, and show how java 24+ fixes enable concurrent io tasks.
Identify thread pinning in Java 21–23 caused by synchronized methods, blocks, or JNI calls; upgrade to Java 24 or above and avoid virtual threads for synchronized io tasks.
Trace thread pinning when using virtual threads by enabling JDK.trace.find-threads in development. Review full or short stack traces to identify synchronized IO in libraries.
Explore fixing thread pinning in virtual threads by replacing synchronized with a reentrant lock, enabling fairness and timeouts, and implementing explicit lock and unlock around the IO-critical section.
Learn to use the thread factory, built from a thread builder, for thread-safe creation of parent and child threads in Java virtual threads.
Explore essential thread methods for virtual threads, including is virtual, join with countdown latch, and interrupt, and learn to parallelize tasks like product and pricing service calls.
Explore how Java virtual threads provide lightweight, non-blocking IO by unmounting from carrier threads and using a fork-join pool with platform threads for OS execution.
Explore how the executor service provides high-level concurrency by managing virtual threads and thread pooling to run parallel airline price checks and find the best deal.
Explore executor service types—fixed, single, cached, scheduled pools—and see how thread-per-task executors with virtual threads deliver non-blocking benefits.
Learn how Java 21 extends ExecutorService with AutoCloseable, use a single-thread executor, submit tasks, and compare shutdown versus shutdown now—plus try-with-resources for short-lived apps.
Explore executor service types, including single thread, fixed, cached, thread-per-task, and virtual thread per task executors, with a demonstration comparing their behavior and a scheduled task example.
Explore a single jar simulating two external microservices (product and rating) with virtual threads, making simple get requests to endpoints, and a configurable port accessible via swagger UI.
Develop a simple external service client in the playground project to fetch data from a local service at localhost:7070 using product and rating endpoints with id-based URLs.
Demonstrates accessing remote responses with future by submitting callables to a virtual-thread executor, awaiting results via future.get, and running parallel product info calls to speed up requests.
Explain how concurrency handles multiple tasks over time and how parallelism uses multiple subtasks to run simultaneously, using Java threads and Java.util.concurrent.
Use the virtual thread executor to submit time consuming tasks and manage future objects. Apply future.get with a timeout to handle timeout exceptions, cancel with future.cancel, and prepare completeable future.
Build a gateway aggregator pattern that calls product and rating backends in parallel using a virtual thread per task executor, returning a combined product dto with id, description, and rating.
Evaluate whether creating two child threads in a virtual-threaded service is needed, or if a single thread can fetch product and rating by awaiting futures.
Understand how the virtual thread executor uses daemon-like threads with no platform threads, letting the app exit after the main thread finishes, while future.get blocks to print results.
Configure a thread factory to name virtual threads in the new thread per task executor, enabling labeled http requests and endpoints by assigning a custom factory.
Explore how Java 21 virtual threads enable non-blocking input/output tasks and compare them with traditional executor services, while examining limitations and challenges for periodic remote calls.
Demonstrates enforcing a three-concurrent-call limit with a fixed thread pool, contrasts with cached pools, and explains why virtual threads are not pooled and should be created per task.
Explore how a semaphore controls concurrency by defining permits, acquiring and releasing them to guard a critical section, with blocking behavior for virtual threads in the JVM.
Builds a concurrency limiter for virtual threads using a semaphore, wraps callables to acquire and release permits, and submits via a wrapped executor service to sustain fixed concurrency.
Investigate how a concurrency limiter interacts with fixed thread pools and virtual threads, and why a thread-per-task executor can break order without a queue.
Implement an ordered concurrency limiter for virtual threads by queuing tasks and letting a concurrent linked queue deliver them in submission order, regardless of thread id.
Explore how to simulate fixed and single executors with virtual threads, and implement a scheduled executor by combining a platform-thread scheduler with a virtual-thread per-task executor for periodic remote calls.
Discover Java 24's stream gatherer and the map concurrent gatherer, enabling custom operators and parallel virtual threads to fetch and collect results.
Explore nested concurrent calls by using stream gatherers to fetch product names and ratings for multiple product ids, with a custom gatherer implementation and virtual-thread patterns for scalable i/o.
Virtual threads are great for tasks but offer little for CPU-intensive work; use a thread-per-task model with an executor service and futures, and avoid pooling virtual threads.
Explore how to use CompletableFuture with virtual threads to build robust asynchronous and concurrent Java programs, including error handling, parallel calls, and combining results.
Explore how CompletableFuture returns a box as a placeholder, enabling non-blocking calls while a time-consuming task completes in the background.
Learn how to create a simple CompletableFuture, complete it with a value, and retrieve it with get or join, then accept the result on a consumer via a virtual thread.
Explore how to use CompletableFuture.runAsync with factory methods and executors, run a runnable asynchronously, switch to virtual thread per task executor, and handle completion with thenRun and exceptionally.
Learn how to supply asynchronous results with CompletableFuture.supplyAsync using a supplier, compare it to runAsync, and use a virtual executor to handle blocking I/O in Java virtual threads.
Pass CompletableFuture.supplyAsync with an executor to retrieve three product information in parallel from an external service, improving error handling while running on virtual threads.
Execute an aggregator demo using CompletableFuture supply async to run product and rating calls in parallel, and handle failures with exceptionally to provide fallbacks like minus one or product not found.
Learn to apply timeout to asynchronous execution with the completeable feature, returning product and rating data with separate timeouts and fallback values, using join to avoid exceptions.
Learn to run parallel product detail calls with CompletableFuture.allOf, supplyAsync with an executor, gather futures, convert to an array, and join to collect results, with timeout considerations.
Learn how to use CompletableFuture.anyOf to race two parallel airfare services, Delta and Frontier, and use the first completed result via a shared executor.
Explore how to use CompletableFuture.thenCombine to merge two futures and select the smaller airfare. Apply a 10% discount using then apply on an immutable airfare record.
Explore how CompletableFuture enables non-blocking, asynchronous processing with error handling and result combination, using a ForkJoinPool or a per-task executor with virtual threads in Java 21.
Master threadlocal and scoped values as per-thread storage that keeps data per thread, without parameter passing; learn benefits, risks, removal needs, and inheritable variants for child threads.
This lecture demonstrates inheritable threadlocal enabling child virtual threads to inherit the parent token, with immutable objects and removal affecting only the executing thread during concurrency.
Use thread local as a disciplined tool by hiding it behind a helper class and always pairing set with remove to manage security request-related metadata, observability, and tracing.
Apply threadlocal to enforce access control in real-world projects by tying a security context to the current thread, with roles admin, editor, viewer, and anonymous, and a login-and-execute workflow.
Implement a document controller that enforces role-based access using a security context supplier, validating viewer, editor, and admin permissions for read, edit, and delete operations.
Validate document access by user role using thread-local security in a document controller demo, enforcing read, edit, and delete permissions across virtual threads.
Explore scoped values in JDK 25, a safer alternative to threadlocal that works with platform and virtual threads. It binds a value to a key and unbinds after runnable completes.
Demonstrates how scoped values work by binding a session token, showing is bound and default value behavior, and illustrating automatic removal after execution.
Replace thread-local storage with scoped values, creating a scoped value key (session token) and using authenticate with runnable blocks on two virtual threads to produce tokens.
Explore scoped values and their rebinding of a session token within a nested scope, switching to an inner token in a runnable and automatically restoring the outer value.
Explore how scoped values store carriers linked by previous references and accessed via dot run and dot get, revealing how long lookups can affect performance and guiding session data design.
Migrate document access from thread local to scoped value by creating a security context key and a get-scoped-value method, then validate admin and editor permissions.
demonstrates using scoped values to temporarily elevate a user from viewer to admin for a task, then automatically revert, illustrated through a document access workflow.
Compare threadlocal and scoped values, highlighting thread-scoped and execution-scoped lifetimes, memory leak risks with threadlocal, and auto-removal of scoped values under structured concurrency in JDK 25+.
Utilize threadlocal for per-thread data and cross-cutting concerns with a private wrapper and paired set‑and‑remove methods, and adopt scoped values in JDK 25 for task-bound data.
Explore structured concurrency as a preview feature in Java, using virtual threads to run subtasks and manage their lifecycle with a structured task scope and joiner strategies.
Explore the await all joiner strategy within a structured task scope by running delta and frontier airfare tasks concurrently, handling success, failure, and unavailable states, and safely querying results.
Learn the any successful result strategy by racing subtasks with scope.join to return the first successful response, cancel remaining tasks, and handle fail cases with potential custom join strategies.
Reveal how structured task scope automatically propagates scoped values to child threads, enabling concurrent product and inventory service calls to access the parent session token.
Develop a Spring application with virtual threads to build a scalable trip-planning API that aggregates data from multiple microservices and supports parallel and sequential workflows, plus scalability testing.
Call external service APIs for accommodation, events, local recommendations, transportation, weather, and flight search/reservation using airport codes to assemble an aggregate travel plan.
Set up a Spring project from start.spring.io with Java, Maven, or Gradle, Spring Boot 3.2+ and Java 21, include web, import into IDE, and scaffold client, config, controller, dtos, service.
Define and implement all required dto models for a travel planning app, including accommodation, events, weather, transportation, trip plan, and flight reservations, using Java records and swagger-driven design.
Use the spring rest client to perform synchronous http requests, replacing rest template, and reuse a single client for get and post operations with url and uri variables, boosting performance.
Create and configure seven dedicated service clients (accommodation, event, recommendation, transportation, weather, flight search, and flight reservation) using a centralized rest client and a config class.
Inject service clients and use an executor service to fetch events, weather, accommodations, transportation, and recommendations in parallel, then assemble a trip plan with safe defaults when a call fails.
Search flights with the flight search service client, pick the best price, then build and submit a flight reservation request via the reservation service client.
Design a trip controller with get plan trip endpoint by airport code and post reserve flight endpoint, wiring plan and reservation services to return trip plan and flight reservation.
Copy and paste the application properties accurately to avoid mistakes, and adjust the port 7070 if needed. Learn how the spring threads flag is initialized and later enabled.
Create and configure all service client beans, build rest clients with a base URL and logger, and implement seven service clients while validating code against the GitHub version.
Create an executor service config with two beans: a virtual thread per task executor and a platform thread executor, conditionally active based on Spring threads virtual enabled.
Enable virtual threads in spring to process trip requests in parallel, returning an aggregate response with airport code, accommodations, weather, transportation, and local recommendation. See parallel service calls speed responses.
Explore scalability testing with jmeter to compare platform and virtual threads on the Trip Advisor app, measuring throughput and response time. Identify factors that affect scalability, including resources.
Define throughput and response time, and show their inverse relationship. Observe how saturation caps throughput and makes response times rise with more concurrent users.
Set up Apache JMeter, an open source performance testing tool, to simulate concurrent user load, measure throughput and response time, and enhance reporting with the plugin manager.
Build a JMeter test script to simulate concurrent users against a REST endpoint, using a thread group and HTTP request, and analyze response time and throughput.
Explore how throughput and response time relate in a demo, showing transactions per second, response time trends over time, and the value of multiple listeners with aggregate and time-based reports.
Use JConsole to monitor memory and thread counts during a JMeter test on the Trip Advisor app. Observe virtual threads alongside platform threads created by the HTTP client behind scenes.
Explore VisualVM for monitoring Java 21 apps, compare with Jconsole, and observe CPU, GC, class loading, and virtual threads while analyzing memory and HTTP client threads to fix issues.
Configure the rest client to use an HttpClient with a virtual thread per task executor when spring.threads.virtual.enabled is true, replacing the platform-thread request factory and ensuring thread counts stay flat.
Use the command line interface for JMeter tests, disable listeners to save memory, ignore warmup results due to JVM delays, and run tests on separate machines.
Create a trip reservation test script in a new JMeter test plan with http post. Configure json body and headers, run test, and verify the response includes a reservation ID.
Run a platform threads baseline to compare with virtual threads, warm up with 20 users, then a 300-user, six-minute load test using JMeter via CLI, saving results.
Analyze platform thread performance during load testing, focusing on throughput and response time; saturation occurs near 200 concurrent requests due to 200 platform threads, prompting scaling with servers or threads.
Analyze virtual thread performance using JMeter with a warmup, 300 users, 300 seconds ramp-up, and 360 seconds of testing, comparing platform-thread and virtual-thread throughput and latency results.
Rerunning with 600 concurrent users shows virtual threads scale well against platform threads, producing flat response times and rising throughput, with about 173,000 requests in ten minutes.
Compare platform threads and virtual threads by running the trip plan api under parallel loads, tuning the executor service, and monitoring thread usage with Visual VM.
Switch to virtual threads, run the warmup and ramped tests with a trip plan file, and compare results to reveal low cpu usage and only 36 threads.
Compare results between platform and virtual threads by loading trip plans and analyzing response time and throughput. Virtual threads achieve higher throughput up to 300 rps with stable response times.
This section shows virtual threads scale better than platform threads by using far fewer threads to handle more requests, while noting CPU, memory, and network limits.
Migrate existing apps to virtual threads for IO tasks, verify synchronized usage, and adopt a thread-per-task executor to avoid expensive platform threads.
Explore next steps in building scalable microservices with virtual threads, reactive web flux, and fast back-end communication via gRPC, rsocket, or Kafka, plus deployment with Docker and Kubernetes.
Java's virtual threads upgrade non-blocking IO but do not kill reactive programming; reactive programming enables stream-based, backpressure-enabled, non-blocking communication using a publisher for responsive systems, as shown by ChatGPT streaming.
Up-to-date with JDK/Java 26: This course covers all the latest Java features, including finalized Scoped Values, the latest preview of Structured Concurrency (JEP 505), and the foundational power of Virtual Threads.
Master modern, high-performance Java concurrency and build applications that scale effortlessly. This course takes you from foundational Multithreading concepts to the cutting edge of Virtual Threads, Structured Concurrency, and Scoped Values, all reinforced with hands-on Spring Boot projects.
Course Highlights:
Understanding Concurrency: Start with the basics. Understand platform threads, their lifecycle, and the challenges of traditional concurrency. Learn why scaling with conventional threads is difficult and how Java Virtual Threads provide a lightweight, high-performance alternative for handling thousands of concurrent tasks efficiently.
ExecutorService Mastery: Dive into ExecutorService and see how it works with both platform threads and virtual threads. Learn to manage concurrency, execute tasks in parallel, and optimize thread usage for scalable applications.
CompletableFuture Integration: Explore CompletableFuture for asynchronous task execution with Virtual Threads. Learn practical patterns for chaining tasks, handling exceptions, and managing timeouts in a clean, declarative way.
ThreadLocal and Scoped Values: Understand ThreadLocal for storing thread-specific context and the challenges it poses. Then explore Scoped Values, the modern alternative that works seamlessly with both platform and virtual threads, avoids memory leaks, and simplifies context propagation.
Structured Concurrency: Get a hands-on introduction to Java’s Structured Concurrency APIs, learning how to manage groups of tasks as a single unit, improve reliability, and simplify lifecycle management of concurrent tasks.
Hands-On Application Development: Apply your knowledge in a Spring Boot Web project using Virtual Threads. Learn how these concurrency concepts integrate into real-world application development.
Performance Testing with JMeter: Test the scalability of your application using JMeter, measuring throughput and response times to ensure optimal efficiency under various workloads.
Migration Made Easy: Conclude the course with a practical migration guide to transition your existing applications to Java Virtual Threads effortlessly. Get ready for a future where your programs effortlessly combine concurrency and scalability.
Don't just learn concurrency. Master the future of high-performance Java. Unlock the full potential of Virtual Threads, Structured Concurrency, and Scoped Values to design the most scalable, efficient, and modern applications on the platform.