store/[org.clojure/clojure "1.8.0"] clj::clojure.core/commute

Official Documentation

Add notes
Arities
==================================================
   [ref fun & args]

Docstring
==================================================
  Must be called in a transaction. Sets the in-transaction-value of
  ref to:

  (apply fun in-transaction-value-of-ref args)

  and returns the in-transaction-value of ref.

  At the commit point of the transaction, sets the value of ref to be:

  (apply fun most-recently-committed-value-of-ref args)

  Thus fun should be commutative, or, failing that, you must accept
  last-one-in-wins behavior.  commute allows for more concurrency than
  ref-set.

Source

(defn commute
  "Must be called in a transaction. Sets the in-transaction-value of
  ref to:

  (apply fun in-transaction-value-of-ref args)

  and returns the in-transaction-value of ref.

  At the commit point of the transaction, sets the value of ref to be:

  (apply fun most-recently-committed-value-of-ref args)

  Thus fun should be commutative, or, failing that, you must accept
  last-one-in-wins behavior.  commute allows for more concurrency than
  ref-set."
  {:added "1.0"
   :static true}

  [^clojure.lang.Ref ref fun & args]
    (. ref (commute fun args)))

Example 1

Edit
(def counter (ref 0))
;; => #'user/counter

;; deciding whether to increment the counter takes the terribly long time
;; of 100 ms -- it is decided by committee.
(defn commute-inc! [counter]
  (dosync (Thread/sleep 100) (commute counter inc)))
;; => #'user/commute-inc!

(defn alter-inc! [counter]
  (dosync (Thread/sleep 100) (alter counter inc)))
;; => #'user/alter-inc!

;; what if n people try to hit the counter at once?
(defn bombard-counter! [n f counter]
  (apply pcalls (repeat n #(f counter))))
;; => #'user/bombard-counter!

;; first, use alter.  Everyone is trying to update the counter, and
;; stepping on each other's toes, so almost every transaction is getting 
;; retried lots of times:
(dosync (ref-set counter 0))
;; => 0

(time (doall (bombard-counter! 20 alter-inc! counter)))
;; > "Elapsed time: 2007.049224 msecs"
;; => (3 1 2 4 7 10 5 8 6 9 13 14 15 12 11 16 17 20 18 19)

;; note that it took about 2000 ms = (20 workers * 100 ms / update)

;; now, since it doesn't matter what order people update a counter in, we
;; use commute:
(dosync (ref-set counter 0))
;; => 0

(time (doall (bombard-counter! 20 commute-inc! counter)))
;; > "Elapsed time: 401.748181 msecs"
;; => (1 2 3 4 5 9 10 6 7 8 11 15 13 12 14 16 19 17 18 20)
;; notice that we got actual concurrency this time.

Uses on crossclj