0% found this document useful (0 votes)
1 views6 pages

Java Concurrency Crash Notes

Uploaded by

Jan Berde
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
1 views6 pages

Java Concurrency Crash Notes

Uploaded by

Jan Berde
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 6

Java Concurrency

Key APIs, pitfalls, and patterns (Java 17 21)


Crash Notes

© 2025 Short reference for students and professionals.


1. Threads model
1.1 Platform vs Virtual Threads
Platform threads: 1:1 OS threads; heavier context switches.
Virtual threads (Java 21): cheap fibers scheduled by JVM; great for IO bound workloads.
// Java 21
try (var executor = java.util.concurrent.Executors.newVirtualThreadPerTaskExecutor())
IntStream.range(0, 1_000).forEach(i -> executor.submit(() -> fetch(i)));
}

1.2 Structured Concurrency


Treat concurrent subtasks as a unit of work; propagate cancel/failure as a group.
// Preview API shape (conceptual)
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
var u = scope.fork(() -> loadUser());
var o = scope.fork(() -> loadOrders());
scope.join(); scope.throwIfFailed();
return merge(u.get(), o.get());
}

Prefer virtual threads for IO; keep CPU bound tasks on bounded pools.
2. Synchronization & atomics
2.1 synchronized vs Lock
synchronized: simple, reentrant, JVM managed; use for straightforward critical sections.
ReentrantLock: tryLock(), interruptible; fair locks when needed; beware of deadlocks.
final ReentrantLock lock = new ReentrantLock();
void safe() {
if (lock.tryLock()) try { critical(); } finally { lock.unlock(); }
}

2.2 Atomics & Adders


AtomicReference/Long/StampedLock for fine grained control; LongAdder for hot counters.
AtomicReference<State> st = new AtomicReference<>(INIT);
st.updateAndGet(s -> s.advance());

Rule: minimize shared mutable state; prefer immutability and message passing.
3. Executors & CompletableFuture
3.1 Pool sizing
CPU bound: size cores; IO bound: use virtual threads or large pools with back pressure.
3.2 CompletableFuture patterns
thenCompose for chaining async steps; thenCombine for fan in; allOf for fan out.
time outs + orTimeout; handle for fallbacks; minimal blocking joins.
CompletableFuture<User> user = api.loadUser(id);
CompletableFuture<List<Order>> orders = api.loadOrders(id);
var result = user.thenCombine(orders, Service::merge)
.orTimeout(3, TimeUnit.SECONDS)
.exceptionally(Service::fallback);

Use CF for composition; avoid nested futures and blocking get().


4. Collections, pitfalls, debugging
4.1 Concurrent collections
ConcurrentHashMap, CopyOnWriteArrayList; beware write heavy patterns with COW.
Map.computeIfAbsent is atomic; no external double checked locking needed.
cache.computeIfAbsent(key, k -> loader.apply(k));

4.2 Common pitfalls


Blocking calls inside synchronized blocks; unbounded queues; swallowing
InterruptedException.
Deadlocks from inverted lock ordering; visibility bugs without volatile/atomics.
4.3 Debugging
Thread dumps (jcmd/jstack); async profiler; allocation tracking.
Add thread names; MDC correlation IDs; structured logs.

Cheat: set -Djdk.tracePinnedThreads=full to catch pinned virtual threads.


5. Cheatsheet
Quick rules
Prefer immutable DTOs; confine mutability; favor message passing.
Virtual threads for IO; bounded pools for CPU work.
Never block inside synchronized; keep critical sections tiny.
Use timeouts, deadlines, and cancellation everywhere.
Measure: p95 latency per step, queue sizes, and pool saturation.

Practice: rewrite a blocking IO service using virtual threads and deadlines.

You might also like