Atomic Counters in Clojure
In Clojure, we can use atoms to manage shared state across multiple threads. This is similar to atomic counters in other languages. Let’s look at how we can implement an atomic counter accessed by multiple threads.
(ns atomic-counters
(:require [clojure.core.async :as async]))
(defn main []
; We'll use an atom to represent our (always-positive) counter.
(let [ops (atom 0)
; We'll use a countdown latch to wait for all threads to finish.
latch (java.util.concurrent.CountDownLatch. 50)]
; We'll start 50 threads that each increment the counter exactly 1000 times.
(dotimes [_ 50]
(async/thread
(dotimes [_ 1000]
; To atomically increment the counter we use swap!
(swap! ops inc))
(.countDown latch)))
; Wait until all the threads are done.
(.await latch)
; Here no threads are writing to 'ops', but using deref it's safe
; to atomically read a value even while other threads might be updating it.
(println "ops:" @ops)))
(main)
In this Clojure version:
We use an
atom
instead ofatomic.Uint64
. Atoms in Clojure provide atomic updates to a single reference.Instead of a
WaitGroup
, we use aCountDownLatch
from Java’s concurrent utilities. This serves a similar purpose of waiting for all threads to complete.We use
async/thread
to create threads, which is similar to goroutines in Go.The
swap!
function is used to atomically update the atom. It’s similar to theAdd
method in Go’s atomic package.We use
@ops
(which is shorthand for(deref ops)
) to read the final value of the atom, similar to theLoad
method in Go.
When you run this program, you should see:
$ clj atomic-counters.clj
ops: 50000
We expect to get exactly 50,000 operations. The use of atoms ensures that all updates to the counter are atomic, preventing race conditions that could occur with non-atomic operations.
This example demonstrates how Clojure’s concurrency primitives, particularly atoms, can be used to safely manage state across multiple threads. While the syntax and specific mechanisms differ from Go, the underlying concept of atomic operations for safe concurrent access remains the same.