Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Race conditions and clojure Atoms

The Documentation for the clojure "atom" states that -

"Changes to atoms are always free of race conditions."

However- a race condition is defined not just in terms of a change , but rather, in context of parallel logical operations in different threads.

I am wondering - what is the significance of the guarantee that "Changes to atoms are always free of race conditions"? In java, we have atomic primitives, which support certain thread-safe operations which are specific (for example, the AtomicInteger supports a "getAndIncrement" operation). But Clojure atoms are type-agnostic, for example, we can invoke :

  (atom "Hi im a string")  Or
  (atom (.getClass Object))

The flexibility of the atom method means that Clojure, under the hood, is not "smartly" providing type-specific atomic / thread-safe operations for atoms.

Thus, I would ask -- what exactly is the atom method "doing" to our objects (i.e. is it simply synchronizing the whole object?)

like image 341
jayunit100 Avatar asked Mar 12 '12 01:03

jayunit100


1 Answers

An atom is effectively an atomic storage location that is guaranteed to be thread safe.

Atoms are similar to Java's atomic data types (like AtomicReference), but are actually somewhat more powerful since an atom allows you to use an arbitrary function to update the atom. Example:

(def a (atom "foo"))

(defn appender [x]
  "Higher order function that returns a function which appends a specific string"
  (fn [s] 
    (str s x)))

(swap! a (appender "bar"))
=> "foobar"

In the above example, the swap! operation behaves atomically, even though the appender operation we are passing to it could potentially be a quite complex function. In effect, atoms allow you to use an arbitrary update operation in an atomic way (you should normally stick to pure functions since it is possible for the function to be called multiple times in the event of contention).

Atoms obviously don't guarantee thread safety of objects you put inside them (e.g. if you put an unsynchronised Java ArrayList inside, then it's still unsafe for concurrent usage). However if you stick to Clojure's immutable data types which are all completely thread safe then you will be good.

like image 190
mikera Avatar answered Nov 02 '22 04:11

mikera