以下程序演示了在使用{{ensure}}时发生的活锁。
(let [cats (ref 1)
dogs (ref 1)
events (atom [])
john (future
(dosync
(swap! events conj :j1)
(when (< (+ @cats (ensure dogs)) 3)
(swap! events conj :j2)
(ref-set cats 2))
(swap! events conj :j3)))
mary (future
(dosync
(swap! events conj :m1)
(when (< (+ (ensure cats) @dogs) 3)
(swap! events conj :m2)
(ref-set dogs 2))
(swap! events conj :m3)))]
@john @mary @events)
; => [:m1 :j1 :m2 :j2 :j1 :m1 :j2 :m2 :j1 :m1 :j2 :m2 :m1 :j1 :j2 :m2 :m1 :j1 :j2 :m2 :m1 :j1 :m2 :j2 :m1 :j1 :j2 :m2 :j1 :m1 :j2 :m2 :m1 :j1 :j2 :m2 :j1 :m1 :m2 :j2 :m1 :j1 :j2 :m2 :m1 :j1 :m2 :j2 :m1 :j1 :j2 :m2 :j1 :m1 :j1 :m2 :j2 :j1 :m3 :j1 :j3]
此程序有时会非常快速终止,但在交易重试数十或数百次后,有时会有几秒钟的延迟。
{{(ensure ref)}}以一种{{(ref-set ref @ref)}}所不具有的方式显示活锁,因为只有后者支持闯关。有了{{ref-set}},较旧的交易最终会胜出,这得益于闯关。有了{{ensure}},由于两个交易都试图获取由另一个交易({{ensure}})持有的读锁的ref的写锁({{ref-set}}),因此没有闯关。两个交易都将闲置整整100ms的超时时间,然后将同时重试。
这可能是对文档的一个增强。句子“比(ref-set ref @ref)具有更高的并发性”在一般情况下可能不正确(无论如何,太笼统了,帮助不大)。{{(ref-set ref @ref)}}比{{(ensure ref)}}更安全。