Featured resource
2026 Tech Forecast
2026 Tech Forecast

1,500+ tech insiders, business leaders, and Pluralsight Authors share their predictions on what’s shifting fastest and how to stay ahead.

Download the forecast
  • Lab
    • Libraries: If you want this lab, consider one of these libraries.
    • Core Tech
Labs

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 platform
Lab Info
Level
Intermediate
Last updated
Apr 01, 2026
Duration
45m

Contact sales

By clicking submit, you agree to our Privacy Policy and Terms of Use, and consent to receive marketing emails from Pluralsight.
Table of Contents
  1. 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:

    1. 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).
    2. 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.

  2. 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: FlightService and HotelService. Each will have a fetchOffer method that simulates an I/O operation (like a network call) by sleeping for a short duration, then returns an Offer object.

  3. 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.

  4. 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, StructuredTaskScope uses joiners to handle task completion. The Joiner.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.

  5. Challenge

    Customizing Thread Creation

    While StructuredTaskScope uses 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 custom ThreadFactory that creates named virtual threads, which is especially useful for debugging and monitoring in production systems. ## Running the App From the workspace/ directory run:

    ./run.sh
    

    This compiles and runs com.example.Main with --enable-preview enabled. No Maven required.

  6. 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 StructuredTaskScope for 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

Pluralsight’s AI authoring technology is designed to accelerate the creation of hands-on, technical learning experiences. Serving as a first-pass content generator, it produces structured lab drafts aligned to learning objectives defined by Pluralsight’s Curriculum team. Each lab is then enhanced by our Content team, who configure the environments, refine instructions, and conduct rigorous technical and quality reviews. The result is a collaboration between artificial intelligence and human expertise, where AI supports scale and efficiency, and Pluralsight experts ensure accuracy, relevance, and instructional quality, helping learners build practical skills with confidence.

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.

Get started with Pluralsight