Supongamos que tiene algunas cuentas bancarias:
(def accounts
[(ref 0)
(ref 10)
(ref 20)
(ref 30)])
Y una función de "transferencia" atómica:
(defn transfer [src-account dest-account amount]
(dosync
(alter dest-account + amount)
(alter src-account - amount)))
Que funciona de la siguiente manera:
(transfer (accounts 1) (accounts 0) 5)
(map deref accounts)
=> (5 5 20 30)
Luego puede componer fácilmente la función de transferencia para crear una transacción de nivel superior, por ejemplo, la transferencia desde varias cuentas:
(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)
Tenga en cuenta que todas las transferencias múltiples ocurrieron en una sola transacción combinada, es decir, fue posible "componer" las transacciones más pequeñas.
Hacer esto con los bloqueos se complicaría muy rápidamente: suponiendo que las cuentas debían bloquearse individualmente, entonces tendría que hacer algo como establecer un protocolo de orden de adquisición de bloqueos para evitar bloqueos. Es muy fácil cometer un error difícil de detectar. STM te salva de todo este dolor.