Oracle Java SE 21 study materials
Oracle Java SE 21 study resources

Oracle Java SE 21: Managing Concurrent Code Execution

Oracle Java SE 21 · Work through your exam, one topic at a time.

All guide sections

Managing Concurrent Code Execution

Threads

Define work with Runnable or Callable. A thread reaches TERMINATED once and never restarts; start() - not run() - begins a new thread of execution. join() waits for completion, sleep() throws InterruptedException, and interrupt() only sets a flag: it does not stop a running thread unless that thread is blocked in an interruptible method.

Executors

Executors.newFixedThreadPool, newSingleThreadExecutor, and newVirtualThreadPerTaskExecutor (Java 21) all return an ExecutorService. execute accepts a Runnable; submit returns a Future and accepts a Callable; invokeAll/invokeAny batch tasks. shutdown() stops accepting tasks but lets running ones finish; shutdownNow() interrupts them. Since Java 19 an ExecutorService is AutoCloseable, so a try-with-resources block shuts it down and awaits termination.

Shared state

synchronized on an instance method locks this; on a static method it locks the Class object; a synchronized block locks whatever object you name. volatile guarantees visibility, not atomicity - use AtomicInteger/LongAdder or a ReentrantLock for compound updates. ConcurrentHashMap forbids null keys and values and offers atomic computeIfAbsent/merge; CopyOnWriteArrayList suits read-heavy lists; BlockingQueue.put/take handle back-pressure.

Traps and modern practice

wait/notify require holding the monitor, and locking on mismatched objects is a classic deadlock source. Virtual threads are cheap and should not be pooled - create one per task. Avoid mutating shared state inside parallel streams, and never rely on HashMap/ArrayList for concurrent writes.

Worked rule: two threads deadlock when they acquire the same pair of locks in opposite order - enforce a global lock ordering.