# How Maven Handles Parallel Builds and Concurrency: A Deep Dive into the Source Code

> Discover how Maven handles parallel builds and concurrency with the -T flag. Explore thread pool configuration, lifecycle phase execution, and failure strategies in this source code deep dive.

- Repository: [The Apache Software Foundation/maven](https://github.com/apache/maven)
- Tags: deep-dive
- Published: 2026-07-05

---

**Maven parallel builds are controlled by the `-T` flag, which configures a fixed-size thread pool that executes lifecycle phases across modules concurrently while enforcing thread-safety checks and respecting the reactor failure strategy.**

Apache Maven supports parallel builds through a sophisticated concurrency engine that transforms the `-T` command-line option into a managed thread pool. This mechanism enables simultaneous execution of independent project modules while maintaining dependency order and validating plugin thread-safety. Understanding this system requires examining the core execution classes in the `apache/maven` repository that parse, propagate, and enforce parallelism throughout the build lifecycle.

## Parsing the `-T` Option and Calculating Concurrency

Maven initiates parallel builds by parsing the `-T` (threads) argument during CLI invocation. The parsing logic converts values like `4`, `1C` (one thread per CPU core), or `2C` (two threads per core) into an integer representing the **degree of concurrency**.

In [`impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvoker.java`](https://github.com/apache/maven/blob/main/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvoker.java) (lines 293-298), the invoker reads the flag and populates the execution request:

```java
// From MavenInvoker.java
request.setDegreeOfConcurrency(threads);

```

The calculation logic resides in [`compat/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java`](https://github.com/apache/maven/blob/main/compat/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java) (lines 1401-1404), which evaluates thread specifications relative to available processors. The parsed value is then stored in `MavenExecutionRequest` and defaults to `1` in [`DefaultMavenExecutionRequest.java`](https://github.com/apache/maven/blob/main/DefaultMavenExecutionRequest.java).

## Thread Pool Creation and Session Propagation

Once parsed, Maven determines the actual thread pool size by comparing the requested degree of concurrency against the number of projects in the reactor. This calculation appears in [`impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/BuildPlanExecutor.java`](https://github.com/apache/maven/blob/main/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/BuildPlanExecutor.java) (lines 100-114):

```java
int threads = Math.min(session.getRequest().getDegreeOfConcurrency(), 
                       session.getProjects().size());
session.setParallel(threads > 1);

```

The [`MultiThreadedBuilder.java`](https://github.com/apache/maven/blob/main/MultiThreadedBuilder.java) class (lines 84-90) performs similar propagation for each `ProjectSegment` in multi-module builds. Maven then instantiates a fixed-size thread pool using `Executors.newFixedThreadPool` with a custom `BuildThreadFactory`, wrapped in a `PhasingExecutor` that manages concurrent lifecycle step execution.

## Weave-Mode Execution and Dependency Scheduling

Maven's default **weave** strategy, implemented in `BuildPlanExecutor`, schedules build steps (setup, mojo execution, teardown) across projects while respecting inter-project dependencies. The `executePlan()` method (lines 81-92) identifies ready steps, while `processStep()` (lines 65-87) determines whether to schedule or skip them based on completion status of predecessor steps.

The `PhasingExecutor` runs these steps concurrently, but only after all dependencies have completed successfully. This ensures that module A compiles before module B (if B depends on A) while allowing independent modules to build simultaneously.

## Thread-Safety Validation

Before parallel execution begins, Maven validates that every mojo (plugin goal) is marked as thread-safe. The `checkThreadSafety()` method in [`BuildPlanExecutor.java`](https://github.com/apache/maven/blob/main/BuildPlanExecutor.java) (lines 108-117) collects executions lacking the `@threadSafe` annotation or Maven-4-compatible markers.

If unsafe mojos are detected, Maven logs a detailed warning identifying the specific plugins and versions. While the build may continue depending on configuration, the system strongly encourages upgrading to thread-safe plugin versions to prevent race conditions and corrupted build outputs.

## Failure Handling in Parallel Builds

Parallel execution respects the reactor failure behavior configured via command-line flags (`-ff` fail-fast, `-fae` fail-at-end, etc.). The `handleBuildError()` method in [`BuildPlanExecutor.java`](https://github.com/apache/maven/blob/main/BuildPlanExecutor.java) (lines 90-106) updates the reactor status when a project fails, which influences subsequent scheduling decisions.

In `failFast` mode, the error handler halts further parallel work immediately. For `failAtEnd`, Maven completes currently running projects but skips dependent modules, aggregating all failures for the final report.

## Configuration API and Programmatic Access

The public API exposes thread configuration through [`MavenOptions.java`](https://github.com/apache/maven/blob/main/MavenOptions.java) (lines 61-66) in `api/maven-api-cli`, defining `Optional<String> threads()`. Developers can query this value programmatically within plugins or extensions:

```java
MavenSession session = ...;
String threads = session.getRequest()
                        .getUserProperties()
                        .getProperty("threads");
System.out.println("Parallel threads: " + threads);

```

Typical command-line usage includes:

```bash

# Run with four worker threads

mvn -T 4 clean install

# Use one thread per CPU core

mvn -T 1C clean verify

# Two threads per core

mvn -T 2C clean package

```

## Summary

- **Maven parallel builds** are activated via the `-T` flag, supporting absolute numbers (`4`) or CPU-relative values (`1C`, `2C`).
- **Thread pool sizing** occurs in `BuildPlanExecutor`, calculating the minimum of requested threads and available projects.
- **Dependency ordering** is preserved through the weave-mode execution strategy, which uses `PhasingExecutor` to schedule steps only after predecessors complete.
- **Thread-safety verification** happens before execution in `checkThreadSafety()`, warning about non-thread-safe plugins.
- **Failure handling** integrates with reactor strategies via `handleBuildError()`, respecting `failFast`, `failAtEnd`, and `failNever` configurations.
- **Programmatic access** is available through `MavenOptions.threads()` and `MavenExecutionRequest` properties.

## Frequently Asked Questions

### How do I enable parallel builds in Maven?

Use the `-T` or `--threads` command-line option followed by a number or CPU multiplier. For example, `mvn -T 4 clean install` uses four threads, while `mvn -T 1C clean install` allocates one thread per CPU core. This value propagates through `MavenExecutionRequest` and configures the thread pool in `BuildPlanExecutor`.

### What does the `C` suffix mean in the `-T` option?

The `C` suffix indicates "per CPU core." Maven calculates the actual thread count by multiplying the number preceding `C` by the available processor cores. For instance, `-T 2C` on an 8-core machine results in 16 threads. This calculation occurs in [`MavenCli.java`](https://github.com/apache/maven/blob/main/MavenCli.java) (lines 1401-1404) before being stored in the execution request.

### Are Maven plugins thread-safe by default?

No. Maven validates thread-safety before parallel execution by checking for the `@threadSafe` annotation or Maven 4 compatibility markers in `BuildPlanExecutor.checkThreadSafety()`. If unsafe plugins are detected, Maven logs a warning listing the specific goals that may cause concurrency issues, though the build may continue depending on configuration.

### How does Maven handle build failures during parallel execution?

Maven respects the configured reactor failure strategy (`-ff`, `-fae`, `-fn`). The `handleBuildError()` method in `BuildPlanExecutor` updates the reactor status, which determines whether to halt immediately (`failFast`), continue with independent projects (`failAtEnd`), or ignore failures entirely (`failNever`). This ensures consistent behavior regardless of which thread encounters the error.