为什么要交换!即使Atom的值未更改也重试一次?

时间:2018-10-27 22:24:14

标签: concurrency clojure

假设我有以下一段(伪造的)Clojure代码:

(def c (clojure.lang.Atom. [nil nil]))
(swap! c 
   (fn [[x y]] 
       ["done", (second (swap! c (fn [[x y]] [x y])))]))

我希望它可以按以下方式工作:

  1. Clojure对c进行拆箱以找到[nil nil],并将其传递到外部fn

  2. 外部fn调用swap!,将c拆箱以找到[nil nil],并将此值传递给内部fn

  3. p>
  4. 内部fn返回[nil nil]。对swap!的内部调用将其交换为c的新值。

  5. 外部fn返回值["done" nil]

  6. 外部swap!尝试访问compare-and-set!,发现c的当前值[nil nil]与旧值{{ 1}},那么它成功了,交换了[nil nil]

但是实际上,这段代码会永远循环:外循环不断重试。

这是为什么?我的心理模型缺少什么?

1 个答案:

答案 0 :(得分:3)

Clojure Slack上的几个人帮助我了解了这里发生的一切(谢谢!)。 compare-and-set!使用identical?(即Java参考相等)比较原子的旧值和新值。每次重新创建向量[x y]时,我都会创建一个新对象,该对象与旧对象不identical?。即使我不认为内部swap!可以使任何事物发生变异,但从技术上讲,它是对的。