В документации к swap! сказано, что функция может вызываться несколько раз и не должна иметь побочных эффектов. А в реальном коде из неё всё равно пишут в лог.
(def hits (atom 0))
(defn record! [id]
(swap! hits (fn [n]
(println "counting" id)
(inc n))))
Значение атома в любом случае правильное, потому что фиксируется только одна попытка. println к этой фиксации не относится. Когда два потока соревнуются, проигравшая попытка уже успела напечатать и выполняется заново, так что на один вызов строка может появиться дважды. Та же картина, что с побочным эффектом внутри dosync, только нарваться проще, потому что ничего не координируется. Я в таких случаях беру swap-vals!. Он возвращает старое и новое значение, и пишу в лог уже после возврата.