- Lab
-
Libraries: If you want this lab, consider one of these libraries.
- Core Tech
Guided: Concurrent Programming with Virtual Threads and Structured Concurrency
In this Code Lab, you'll build a Travel Deal Aggregator using Java's modern concurrency features from Project Loom. You will learn to use virtual threads for lightweight, scalable tasks and structured concurrency to manage them reliably, ensuring your application is both efficient and resilient.
Lab Info
Table of Contents
-
Challenge
Introduction to Modern Java Concurrency
Welcome to this Code Lab on Concurrent Programming with Virtual Threads and Structured Concurrency!
For years, Java's concurrency model has been built on platform threads, which are a scarce resource mapped directly to operating system threads. This model can become a bottleneck in I/O-bound applications that need to handle many concurrent connections.
Project Loom, now a standard part of Java 25, introduces two revolutionary features to solve this:
- Virtual Threads: Extremely lightweight threads managed by the JVM, not the OS. You can have millions of them, making them perfect for tasks that spend most of their time waiting for I/O (like network calls or database queries).
- Structured Concurrency: A new API that treats multiple related tasks running in different threads as a single unit of work. It simplifies error handling, cancellation, and resource management, eliminating common pitfalls like thread leaks.
You'll build a Travel Deal Aggregator that fetches data from multiple sources concurrently, applying these modern concepts to write code that is simpler, more reliable, and more scalable than traditional approaches.
info> This lab experience was developed by the Pluralsight team using Forge, an internally developed AI tool utilizing Gemini technology. All sections were verified by human experts for accuracy prior to publication. For issue reporting, please contact us.
-
Challenge
Creating the Service Layer
Before you dive into concurrent programming, let's start by creating the foundational service classes that our aggregator will use. These services simulate fetching travel deals from different providers. They are simple, synchronous services that will later be orchestrated using structured concurrency.
You'll create two service classes:
FlightServiceandHotelService. Each will have afetchOffermethod that simulates an I/O operation (like a network call) by sleeping for a short duration, then returns anOfferobject. -
Challenge
Implementing Structured Concurrency
Now that you have your service classes, it's time to orchestrate them concurrently using structured concurrency. Structured concurrency enforces a clear hierarchy: tasks must complete before their parent scope can exit. This guarantees that you can't leak threads and makes your program's flow much easier to reason about.
The central piece of this API is the
StructuredTaskScope. You'll create a scope, fork tasks within it, and then join them. When you fork a task, it automatically runs in a virtual thread, giving you the benefits of lightweight concurrency without the complexity of manual thread management.Put this into practice to build the aggregator that fetches deals from all three services concurrently.
-
Challenge
Handling Failures and Timeouts
Real-world systems are unreliable. Services can fail or respond slowly. Structured concurrency provides elegant solutions for these common problems.
In Java 25,
StructuredTaskScopeuses joiners to handle task completion. TheJoiner.allSuccessfulOrThrow()joiner automatically cancels all other running tasks in the scope as soon as one fails, making it highly efficient by preventing wasted time and resources on operations that are no longer relevant. You'll also configure timeouts using the scope's configuration API to enforce deadlines for an entire group of concurrent tasks. -
Challenge
Customizing Thread Creation
While
StructuredTaskScopeuses virtual threads by default, you can customize the thread factory to control how threads are created. This allows you to set custom thread names, priorities, or other thread attributes. You'll configure a customThreadFactorythat creates named virtual threads, which is especially useful for debugging and monitoring in production systems. ## Running the App From theworkspace/directory run:./run.shThis compiles and runs
com.example.Mainwith--enable-preview enabled. No Maven required. -
Challenge
Conclusion and Debugging Benefits
Congratulations on completing the Code Lab!
You have successfully built a concurrent application using Java 25's latest and greatest features. You've learned how to:
- Create simple service classes that can be orchestrated concurrently.
- Group tasks with
StructuredTaskScopefor clean, predictable lifecycles. - Handle errors and cancellations gracefully using joiners.
- Enforce deadlines for concurrent operations using scope configuration.
- Customize thread creation with thread factories.
One of the most powerful but subtle benefits of this model is debuggability. With structured concurrency, the call stack of a virtual thread includes the caller's stack. If a task fails, the stack trace clearly shows the entire causal chain, from the parent scope down to the error. This is a massive improvement over asynchronous callbacks or separate thread pool submissions, where context is often lost.
By adopting these patterns, you can write concurrent Java code that is not only highly scalable but also significantly easier to write, read, and maintain.
About the author
Real skill practice before real-world application
Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.
Learn by doing
Engage hands-on with the tools and technologies you’re learning. You pick the skill, we provide the credentials and environment.
Follow your guide
All labs have detailed instructions and objectives, guiding you through the learning process and ensuring you understand every step.
Turn time into mastery
On average, you retain 75% more of your learning if you take time to practice. Hands-on labs set you up for success to make those skills stick.