Browse Clojure Foundations for Java Developers

Comparing Java and Clojure Concurrency Models

Translate familiar Java concurrency tools into Clojure’s reference-and-value model.

If you learned concurrency in Java, your mental toolbox likely includes synchronized, locks, volatile, concurrent collections, and executors. Those tools are still there—Clojure runs on the same JVM—but Clojure’s defaults push you toward a different structure:

  • Immutable values reduce the amount of shared mutable state.
  • References make “the stateful part” explicit and localizable.
  • Update-with-a-function replaces many “read-modify-write” races.

Practical mappings (not exact, but useful):

  • AtomicReference → atom (swap!)
  • “Multiple values must change together” → refs + STM (dosync)
  • “Background updates in order” → agent (send)
  • “Message passing / pipelines” → channels (core.async) or queues

This section is about translating intent: what you were trying to achieve in Java, and how to do it in Clojure without recreating lock-heavy designs.

In this section

Revised on Friday, April 24, 2026