以下程序演示了使用{{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 :m2 :j2 :j1 :m1 :m2 :j2 :m1 :j1 :j2 :m2 :m1 :j1 :m2 :j2 :m1 :j1 :j2 :m2 :m1 :j1 :j2 :m2 :m1 :j1 :j2 :m2 :m1 :j1 :m2 :j2 :m1 :j1 :j2 :m2 :m1 :j1 :m2 :j2 :m1 :j1 :j2 :m2 :m1 :j1 :m2 :j2 :m1 :2 :j1 :j3]
这个程序有时会很快终止,但有时会因为几十或几百次的尝试而延迟几秒钟。
{{(ensure ref)}}以一种方式表现出活锁,而这种方式与等价的{{(ref-set ref @ref)}}不同,因为只有后者支持闯入。随着{{ref-set}},由于闯入,最终旧事务将会获胜。在{{ensure}}中,没有闯入,因为两个事务都尝试获得由另一个事务({{ensure}})持有的 ref 的写锁({{ref-set}})。两个事务都将空闲100毫秒的超时时间,然后同时重新尝试。
这可能是对文档的增强。句子“允许比(ref-set ref @ref)更高的并发性”在一般情况下可能不正确(无论如何,这太模糊了,没有太大帮助)。{{(ref-set ref @ref)}}比{{(ensure ref)}}更安全。