All Java templates

Java Virtual Threads & Concurrency

Project Loom virtual threads, structured concurrency, and modern concurrent patterns.

DevZone Tools1,920 copiesUpdated Apr 4, 2026Java
# CLAUDE.md — Java Virtual Threads & Concurrency

## When to use virtual threads

- Java 21+. Virtual threads scale to millions of concurrent tasks for I/O-bound work.
- Use them when you'd previously have used a thread pool sized in the hundreds. They're cheaper than OS threads.
- **Don't** use them for CPU-bound work. They run on a fixed pool of carrier threads — bottleneck is the same.
- **Don't** use them inside `synchronized` blocks that span I/O. Pinning to a carrier thread negates the benefit. Use `ReentrantLock` instead.

## How to spawn

- One-off: `Thread.startVirtualThread(() -> work())`.
- Pool-style: `Executors.newVirtualThreadPerTaskExecutor()` — every task gets its own virtual thread, no reuse.
- Don't `setMaxThreads` — there's no useful upper bound.

## Structured concurrency

- `StructuredTaskScope` for fan-out/fan-in. Lifetime is tied to the enclosing scope:
  ```java
  try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
      var a = scope.fork(() -> fetchA());
      var b = scope.fork(() -> fetchB());
      scope.join().throwIfFailed();
      return new Pair<>(a.get(), b.get());
  }
  ```
- `ShutdownOnFailure` cancels siblings on first failure. `ShutdownOnSuccess` returns first success.
- Always call `scope.join()` — the try-with-resources only closes the scope, not the work.

## CompletableFuture

- Still useful for callback-style composition.
- Prefer `thenApply`, `thenCompose`, `thenCombine` over chained `whenComplete`.
- Always specify the executor (`*Async` variants take one). The common pool surprises you.

## Locks

- `ReentrantLock` for non-trivial locking. `synchronized` is fine for short critical sections.
- `ReadWriteLock` only when reads dominate writes by an order of magnitude. Otherwise it's slower than `Lock`.
- `StampedLock` for optimistic reads. Read the JavaDoc — it's not a drop-in replacement.

## Atomics

- `AtomicInteger`, `AtomicReference` for lock-free counters and references.
- `LongAdder` over `AtomicLong` when many threads write and few read. Better contention behavior.
- Use `volatile` only for write-once-publish or visibility-only flags. Compound operations need atomics.

## Cancellation

- Always honor `Thread.interrupted()` in long loops.
- `InterruptedException`: catch, restore the flag (`Thread.currentThread().interrupt()`), and bail out.
- Don't swallow interrupts. They're a cancellation signal from the caller.

## Don't

- Don't sleep in I/O code. If you need a timeout, use `CompletableFuture.orTimeout(...)`.
- Don't pin virtual threads inside `synchronized` blocks holding I/O calls.
- Don't share mutable collections across threads. Use `ConcurrentHashMap` or copy-on-write variants.
- Don't use `Thread.stop()`. Ever.

Other Java templates