我有这个代码:
(defn on-thread [f]
(.start (Thread. f)))
(def myref (ref 0))
(on-thread
#(loop [x 100]
(when (> x 0)
(do
(Thread/sleep 100)
(println "myref is:" @myref)
(recur (dec x))))))
(on-thread
#(dosync
(println "transaction1 initial:" @myref)
(alter myref inc)
(println "transaction1 final:" @myref)
(Thread/sleep 5000)
(println "transaction1 done")))
(on-thread
#(dosync
(println "transaction2 initial:" @myref)
(Thread/sleep 1000)
(alter myref inc)
(println "transaction2 final:" @myref)
(println "transaction2 done")))
当我运行这个时,很明显第一个事务首先运行,并且它将 ref 的值更改为 1 - 但其他线程看不到这一点:好的,当然,因为第一个事务尚未完成然而。所以我认为此时此刻还没有“提交”回到裁判。
但此时,第一个事务进入休眠状态,在 sleep 期间,第二个事务尝试更改 ref 的值。它会被回滚,并被环境重试! 为什么? 第二个事务如何“看到”第一个事务的引用发生了(或将要发生)某些事情?
我认为,如果第二个事务能够更改 ref 的事务中值(从 0 到 1),然后 sleep 1000,最后成功提交,然后是第一个事务,那会更符合逻辑将重试。 但事实并非如此。
为什么?
最佳答案
重试第二个事务是因为当它去更改您的引用时,它发现它已经被另一个未提交的事务更改了。因此,它会重试,直到第一个事务提交。
如果万一第二个事务首先更改了引用,那么是的,第一个事务将被重试。然而,事实并非如此,因为第二个事务发生的时间比第一个事务晚得多(以 CPU 时间计算)。
关于Clojure ref - 有什么理由重试此事务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10324703/