你好,
我在 REPL 中的 ref 问题上遇到了一些奇怪的行.
所以我有一个具有简单监视器的 ref
(defn watcher [_ r o n]
(printf "ref: %s old: %s new: %s time: %d\n" @r o n (System/currentTimeMillis))
(flush))
(def x (ref 2))
(add-watch x nil watcher)
然后我连续两次评估以下表达式
(future (dosync (ensure x) (Thread/sleep 3000) (alter x * 2)))
我期望监视器函数会连续两次打印 ref 的值,每次大约 3 秒。
但没有发生任何事情。
当我尝试用另一个命令访问 ref 时,例如
(dosync (ensure x) (alter x inc))
REPL 完全挂起。一次我获得了预期的结果几分钟 later,另一次我获得了这个错误消息
Execution error at reftest.core/eval24449 (form-init12758928819079876959.clj:34).
Transaction failed after reaching retry limit
我觉得奇怪的是,当我评估这个 let-block 时,一切似乎都很好
(let [x (ref 2)]
(add-watch x nil watcher)
(println "start:" (deref x))
(future (dosync (ensure x) (Thread/sleep 3000) (alter x * 2)))
(future (dosync (ensure x) (Thread/sleep 3000) (alter x * 2)))
(dosync (ensure x) (alter x inc))
(println "end:" @x))
REPL 的这种行为是某种类型的错误,还是我做错了什么?
我如何确保这样的 STM 事务在实际代码中不会失败?