warming up your workspace

Concurrency in Java

Explore how Java programs coordinate work. Investigate threads, shared state, synchronisation, and concurrent structures before building a job system.

What helps

Java classes, methods, and collections provide useful preparation. Use Foundations first if you need a language introduction, then move carefully through the thread and shared-state projects.

Java pathway

Programming Foundations / Practice rooms / Track curriculum and enrollment

  1. Threads & Runnables

    A thread is a second line of execution running inside your program. This project covers the mechanics: starting a thread to run a piece of code, waiting for it to finish with join, the difference between run and start, interrupting and sleeping, and getting results back out. It ends by splitting a real computation across several threads and combining the parts, the shape of every parallel algorithm that follows. Because each thread here writes to its own slot and we always join before reading, the results are fully deterministic, no synchronization needed yet.

    • Creating Threads: 5 lessons
    • Joining & Lifecycle: 5 lessons
    • Sleeping & Interrupts: 5 lessons
    • Returning Results: 5 lessons
    • A Parallel Computation: 5 lessons
  2. Shared State & Races

    When two threads touch the same data, the trouble starts. This project makes that trouble concrete and, crucially, deterministic, by modeling interleavings as data rather than gambling on a real race to misbehave. You will simulate the read-modify-write steps behind a lost update, see why an increment must be atomic, reason about visibility as a happens-before graph, model mutual exclusion as critical-section occupancy, and watch a bank's money vanish under a bad interleaving and stay put under a lock. Understand the failure here and the fixes in the next projects will make sense.

    • The Lost Update: 5 lessons
    • Atomicity: 5 lessons
    • Visibility & Happens-Before: 5 lessons
    • Mutual Exclusion: 5 lessons
    • A Bank Invariant: 5 lessons
  3. Synchronization

    Now the fixes, with real threads. A synchronized block or lock makes a critical section run by one thread at a time, so a counter incremented by eight threads lands on exactly the right total, every run. This project builds thread-safe code you can trust: synchronized methods and a shared counter and id generator, the explicit ReentrantLock, guarded blocks with wait and notify and a bounded buffer built by hand, a bank whose balances stay correct under contention, and a thread-safe accumulator. Every test starts many threads, joins them, and checks a settled invariant, the only way to test concurrency without flakiness.

    • synchronized: 5 lessons
    • Explicit Locks: 5 lessons
    • Guarded Blocks & a Buffer: 5 lessons
    • A Thread-Safe Bank: 5 lessons
    • A Thread-Safe Accumulator: 5 lessons
  4. Atomics & CAS

    Locks are not the only way to be safe. The java.util.concurrent.atomic classes offer variables whose operations are indivisible without any locking, built on the hardware's compare-and-set instruction. This project uses atomic counters that reach their exact total under contention, the CAS retry loop that makes a lock-free increment, an AtomicReference holding the head of a Treiber lock-free stack, functional updates and the high-throughput LongAdder, and a lock-free accumulator. No locks held, no threads blocked, and still perfectly correct.

    • Atomic Counters: 5 lessons
    • Compare-and-Set: 5 lessons
    • AtomicReference & a Stack: 5 lessons
    • Functional Updates & Adders: 5 lessons
    • A Lock-Free Engine: 5 lessons
  5. The Java Memory Model

    A race is not only about interleaving; it is about whether one thread can see another's writes at all. The Java Memory Model defines that with happens-before: if one action happens-before another, the first's effects are visible to the second. This project models the relation and its rules, thread start and join, monitor release and acquire, then shows volatile establishing visibility (including a real handoff between threads), what safe publication means, why final fields and immutability make sharing safe, and how double-checked locking goes wrong without volatile and right with it.

    • Happens-Before: 5 lessons
    • volatile: 5 lessons
    • Safe Publication: 5 lessons
    • Immutability: 5 lessons
    • Double-Checked Locking: 5 lessons
  6. Executors & Thread Pools

    Creating a thread per task does not scale: thread creation is expensive and unbounded threads exhaust the machine. An executor decouples submitting work from running it, handing tasks to a managed pool of worker threads. This project uses ExecutorService to submit Runnables and Callables, collects results through Futures and invokeAll, then builds a fixed thread pool from scratch out of a blocking task queue and worker threads, and finishes with a parallel task engine. Every result is read through get or after awaitTermination, so the tests are exact.

    • ExecutorService: 5 lessons
    • Callable & Future: 5 lessons
    • invokeAll & Batches: 5 lessons
    • Build a Thread Pool: 5 lessons
    • A Parallel Task Engine: 5 lessons
  7. Coordination & Synchronizers

    Beyond mutual exclusion, threads need to coordinate: wait for each other, gather at a barrier, limit how many run at once. The java.util.concurrent synchronizers package these patterns. This project builds guarded blocks with wait and notify, counts workers down to a finish line with CountDownLatch, gathers parties at a CyclicBarrier, bounds concurrency with a Semaphore, and runs producers and consumers over a BlockingQueue. Each test waits for the coordinated state to settle, then checks it, so the results are exact.

    • wait & notify: 5 lessons
    • CountDownLatch: 5 lessons
    • CyclicBarrier: 5 lessons
    • Semaphore: 5 lessons
    • Producer-Consumer: 5 lessons
  8. Concurrent Data Structures

    A plain HashMap or ArrayList corrupts under concurrent writes. This project builds thread-safe collections and uses the JDK's: a synchronized stack and queue, a map sharded into independently-locked stripes for better parallelism, the lock-free ConcurrentHashMap with its atomic merge and compute, and the read-optimized CopyOnWriteArrayList. It ends with a concurrent word-count engine that tallies a stream of words across many threads and lands on the exact totals.

    • A Thread-Safe Stack: 5 lessons
    • A Thread-Safe Queue: 5 lessons
    • Concurrent Maps: 5 lessons
    • Copy-on-Write & Snapshots: 5 lessons
    • A Concurrent Word Count: 5 lessons
  9. Hazards & Patterns

    Even correct locking can deadlock if two threads grab the same locks in opposite orders. This project makes the hazards concrete: deadlock as a cycle in a wait-for graph, livelock and starvation, and the patterns that prevent them, acquiring locks in a global order, confining state to one thread, and handing off immutable snapshots instead of sharing mutable state. The failure modes are modeled deterministically; the fixes run on real threads and finish every time.

    • Deadlock: 5 lessons
    • Lock Ordering: 5 lessons
    • Livelock & Starvation: 5 lessons
    • Thread Confinement: 5 lessons
    • Safe Patterns: 5 lessons
  10. Capstone: A Concurrent Job System

    The finale assembles everything into one working system: a job system that takes a batch of jobs, spreads them across a pool of worker threads pulling from a shared blocking queue, collects the results safely, and reports aggregate statistics, exactly, every run. You will build the job and result model, the blocking queue, the worker pool with clean shutdown, the result collection, and finally the complete JobSystem class. By the end you have a small but real concurrent engine, built from threads, queues, atomics, and the safe patterns of the whole track.

    • Jobs & Results: 5 lessons
    • The Job Queue: 5 lessons
    • The Worker Pool: 5 lessons
    • Submission & Collection: 5 lessons
    • The Complete System: 5 lessons