Skip to content
Ameen Abozaid
MID-004

Thread safety

  • 9 Lessons
  • 4 h practice (estimate)
On this page 8 topics

Overview

Topics

  • Race conditions
  • synchronization
  • locks
  • volatile
  • atomics

Learn first

4 h of practice (estimate)

Learning outcomes

  1. Identify race conditions and check-then-act bugs in code review.
  2. Explain visibility and the Java Memory Model's happens-before at a practical level.
  3. Choose between synchronized, ReentrantLock, volatile, and atomics.
  4. Prefer immutability and confinement over locking, and avoid deadlocks with lock ordering.

Lessons

  1. 01Race conditions
  2. 02Visibility and happens-before
  3. 03synchronized and intrinsic locks
  4. 04Explicit locks
  5. 05volatile and atomics
  6. 06Immutability and confinement
  7. 07Deadlocks
  8. 08Demo: reproducing a race with a stress test
  9. 09Demo: diagnosing a deadlock from a thread dump

Lab and exercises

Lab

MID-004-LAB1 · Stock counter

Outcomes: 1–4 · Time: ~4 h Take an in-memory stock counter with a check-then-act race. Write a stress test that fails. Fix it three ways: (1) a lock (synchronized or ReentrantLock), (2) AtomicInteger with compare-and-set, (3) an immutable snapshot swapped through AtomicReference. Compare correctness, throughput, and code clarity. Acceptance: a stress test fails before and passes after each fix.

Exercises (assessment: five snippets with concurrency bugs)

IDOutcomeTask
MID-004-EX011Snippet: lazy singleton if (inst == null) inst = new X();. Identify the race and fix it.
MID-004-EX021Snippet: if (!map.containsKey(k)) map.put(k, v) on a synchronizedMap. Explain the bug and fix it.
MID-004-EX032Snippet: a plain boolean stop flag read in a loop. Explain the visibility problem and fix it.
MID-004-EX044Snippet: a @Service with a List<Order> field. Explain the risk and two redesigns.
MID-004-EX054Snippet: two methods locking a then b, and b then a. Show the deadlock and the fix.
Show solutions
  • EX01 Two threads can both see null. Fix with a holder class, an enum, synchronized, or volatile plus double-checked locking.
  • EX02 The check and put are separate; use ConcurrentHashMap.putIfAbsent or computeIfAbsent.
  • EX03 Without a happens-before edge the loop may never see the write; make the flag volatile (or use interruption).
  • EX04 One shared instance across requests; make it stateless, pass data as parameters, or use a thread-safe structure or per-request object.
  • EX05 Thread 1 holds a waiting for b; thread 2 the reverse. Always lock in one order (for example by id).
  • Outcome 3 (choice of tool) is covered by the lab's three fixes and Q05-Q08 (including volatile with ++, which needs an atomic).

Quiz

Outcomes: O1 races · O2 visibility and happens-before · O3 choosing tools · O4 immutability and deadlocks.

A self-check for you: nothing is graded, saved or sent anywhere. Choose an answer, then check it. You can try again as often as you like.

  1. 1if (stock > 0) stock--; on shared state is an example of:O1
  2. 2count++ is unsafe because it is:O1
  3. 3Which creates a happens-before edge?O2
  4. 4A plain flag read in a loop may:O2
  5. 5volatile alone is enough for:O3
  6. 6For a single lock-free counter, prefer:O3
  7. 7ReentrantLock is chosen over synchronized mainly to get:O3
  8. 8Where does lock.unlock() belong?O3
  9. 9A safe lock object is:O4
  10. 10Deadlock from opposite lock order is prevented by:O4

Practical part

Five exercises MID-004-EX01 to EX05 (the five concurrency-bug snippets) plus the lab. Pass: at least four snippets correct and a stress test that fails before and passes after each of the three fixes.

Common mistakes

volatile for compound actions; locking on mutable or public objects; state in Spring singletons.

Assessment

Find concurrency bugs in five snippets.

Career relevance

Essential for any shared state; distributed analogues in MID-032.

Type to search levels, phases, modules and lessons.