The concurrency toolkit
synchronized, locks, volatile, atomics, concurrent collections, executors, CompletableFuture, virtual threads and structured concurrency.
Two separate questions.
How do threads share data safely?
- Best: don't share. Confine data to one thread, or share only immutable objects.
- One counter or flag → an atomic variable (
AtomicInteger,LongAdder). - A shared map →
ConcurrentHashMapand its atomic methods (merge,computeIfAbsent). - Several fields that must change together →
synchronizedor aReentrantLock, always taking several locks in the same order. - A flag one thread writes and others only read →
volatile.
How do you run work concurrently?
- A batch of tasks → an
ExecutorService; for blocking I/O, one virtual thread per task. - A chain of asynchronous steps →
CompletableFuture. - Subtasks that must succeed or fail together → structured concurrency.
The problems
Example
count++ from two threads loses increments.Two threads' steps interleave and an update is lost.
Section
Race conditions
Read-modify-write, check-then-act, and how to find them.
Term
deadlock
Each thread holds a lock the other needs.
Section
Deadlock
Lock ordering and timeouts.
Sharing data safely
Section
synchronized, locks and volatile
Mutual exclusion and visibility.
One variable updated atomically without a lock.
A map many threads can update at once.
Lock-free counters and thread-safe collections.
Running work
A pool that runs submitted tasks and hands back futures.
Submitting tasks and collecting results.
Section
CompletableFuture
Chaining asynchronous steps.
A cheap thread for blocking work; millions can exist.
Section
Structured concurrency
Subtasks that start, fail and finish together.