以下程序演示了使用 {{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 :m1 :j1 :j2 :m2 :m1 :j1 :m2 :j2 :m1 :j1 :j2 :m2 :m1 :j1 :m2 :j2 :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 :j1 :j2 :m2 :j1 :m3 :j1 :j3]
这个程序有时会非常迅速地终止,但有时由于事务尝试几十或几百次,可能会有几秒钟的延迟。
{{(ensure ref)}} 可能以{{(ref-set ref @ref)}}不可能的方式表现出死锁,因为这些后者支持barging。有了{{ref-set}},旧的交易最终由于barging而获胜。使用{{ensure}}时,没有barging,因为两个事务都试图获取由另一个事务({{ensure}})持有的ref的写入锁({{ref-set}})。两个事务完全空闲了100毫秒的超时时间,然后同时重试。
这可能只是一个文档增强。语句“允许比(ref-set ref @ref)有更高的并发性”可能通常并不正确(无论如何,这太模糊,没有太大帮助)。((ref-set ref @ref))比((ensure ref))更安全。