← The curriculum
§ 7.01 · Concurrency

Threads, executors, and virtual threads

From `Thread` to `ExecutorService` to Project Loom — concurrency the modern way.

Advanced · 40 minute read
Try it yourself
Live Java · editable

Runs on a sandboxed JVM via the public Piston API. Edit the code and hit Run.

§ 7.01.01

Threads: the low-level primitive

new Thread(runnable).start() creates a platform thread mapped 1:1 to an OS thread. Threads are expensive — a few MB of stack each — so creating them per task doesn't scale. You rarely instantiate Thread directly in modern code; you hand tasks to an executor.

§ 7.01.02

ExecutorService

Executors.newFixedThreadPool(n) reuses a bounded pool of threads. submit(Callable) returns a Future you can .get() for the result. Always shut down the pool: try (var pool = Executors.newFixedThreadPool(4)) { ... } uses try-with-resources (Java 19+) to close it cleanly.

§ 7.01.03

Virtual threads (Project Loom)

Java 21 finalized virtual threads — lightweight threads scheduled by the JVM on top of a small pool of carrier threads. You can spawn millions of them. They shine for I/O-bound work: blocking code (Thread.sleep, blocking I/O) becomes cheap because the JVM parks the virtual thread and reuses the carrier for other work.

Example
Live Java · editable

Runs on a sandboxed JVM via the public Piston API. Edit the code and hit Run.

§ 7.01.04

CompletableFuture

For chained async work without blocking, use CompletableFuture. supplyAsync starts a computation, thenApply transforms the result, thenCompose chains another async step, exceptionally recovers from failure. It's Java's answer to promises.

§ 7.01.05

Shared state and locks

Concurrency bugs are almost always about shared mutable state. Prefer immutable data and message-passing. When you must share, use AtomicInteger/AtomicReference for single fields, ReentrantLock or synchronized for compound updates, and ConcurrentHashMap for maps. Never assume HashMap is safe under concurrent writes — it isn't, and the failure mode is data corruption, not an exception.

§ 7.01.06

Structured concurrency (preview)

The StructuredTaskScope API (finalized in Java 21+) treats a group of concurrent subtasks as a single unit of work — they succeed or fail together, and the parent waits for all of them. It removes an entire class of leak bugs and pairs beautifully with virtual threads.