嗨 ,
我在REPL上玩弄refs时遇到了一些奇怪的行为。
因此我有一个带有简单监视功能的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完全锁定。一次我过了几分钟才得到预期的结果,另一次我却得到了这个错误信息
Execution error at reftest.core/eval24449 (form-init12758928819079876959.clj:34).
Transaction failed after reaching retry limit
我发现令人困惑的是,当我在该let块中进行评估时,一切似乎都工作正常
(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事务在真实代码中不会失败?