Припустимо, у вас є кілька банківських рахунків:
(def accounts
[(ref 0)
(ref 10)
(ref 20)
(ref 30)])
І атомна функція "передачі":
(defn transfer [src-account dest-account amount]
(dosync
(alter dest-account + amount)
(alter src-account - amount)))
Що працює наступним чином:
(transfer (accounts 1) (accounts 0) 5)
(map deref accounts)
=> (5 5 20 30)
Потім ви можете легко скласти функцію передачі, щоб створити транзакцію вищого рівня, наприклад переказ з декількох облікових записів:
(defn transfer-from-all [src-accounts dest-account amount]
(dosync
(doseq [src src-accounts]
(transfer src dest-account amount))))
(transfer-from-all
[(accounts 0) (accounts 1) (accounts 2)]
(accounts 3)
5)
(map deref accounts)
=> (0 0 15 45)
Зауважте, що всі численні передачі відбувалися в одній комбінованій транзакції, тобто можна було "скласти" менші транзакції.
Зробити це з блокуваннями буде дуже складно: припустивши, що облікові записи потрібно блокувати індивідуально, тоді вам потрібно зробити щось на кшталт встановлення протоколу замовлення на придбання блокування, щоб уникнути тупикових ситуацій. Зробити важко виявлену помилку дуже просто. STM рятує вас від усього цього болю.