嗨,
在使用 REPL 中的引用时,我发现了一些奇怪的行为。
因此,我有一个具有简单监视器函数的引用
(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)))
我预计监视器函数应该连续打印两次引用的值,大约每3秒钟一次。
但是没有任何反应。
然后我尝试使用其他命令来访问引用,如
(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事务不会在真实代码中失败?