2

我有这个代码:

(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 - 但其他线程看不到这一点:好吧,当然,因为第一个事务尚未完成。所以我认为此时还没有“提交”给裁判。

但是此时,第一个事务进入睡眠状态,当它处于睡眠状态时,第二个事务尝试更改 ref 的值。它被回滚,并被环境重试!为什么?第二笔交易如何“看到”第一笔交易的 ref 发生了(或将要发生)某事?

我认为如果第二个事务能够更改 ref 的事务中值(从 0 到 1)然后休眠 1000,然后最终成功提交,那么将重试第一个事务会更合乎逻辑. 但这种情况并非如此。

为什么?

4

1 回答 1

2

第二个事务被重试,因为当它改变你的 ref 时,它看到它已经被另一个未提交的事务改变了。因此,它会重试,直到第一个事务提交。

如果有某种机会,第二个事务首先更改了 ref,那么是的,第一个事务将被重试。但是,事实并非如此,因为您的第二个事务发生在第一个事务之后(在 CPU 时间中)。

于 2012-04-25T23:10:00.893 回答