clojure - 如果线程在 `swap!` 期间更改原子的值会发生什么?

标签 clojure

根据官方 Clojure docs :

Since another thread may have changed the value in the intervening time, it [swap!] may have to retry, and does so in a spin loop.

这是否意味着执行交换的线程可能会永远卡在 swap! 中,如果有问题的原子永远不会返回到 swap! 读取的值?

最佳答案

是的。如果你有一个非常慢的突变与大量快速操作竞争,慢速操作将不得不每次重试,并且直到所有快速操作完成后才会完成。如果快速操作无限期地进行,那么慢速操作将永远不会完成。

例如,尝试:

(time 
  (let [a (atom 0)] 
    (future (dotimes [_ 1e9] (swap! a inc))) 
    (swap! a (fn [x] (Thread/sleep 1000) (* 2 x)))))

首先,您会发现它需要很长时间才能完成,比一秒钟要长得多。这是因为在较小的任务全部完成之前,循环外的 swap! 无法取得任何进展。您还会看到得到的答案恰好是 2000000000,这意味着加倍操作肯定是最后发生的,在每次递增之后。如果有更多的增量,它们都会获得“优先级”。

我还想到了一些可爱的方法来永远死锁一个原子,而根本不会占用任何更多线程!

一种方法是让线程与自身竞争:

(let [a (atom 0)]
  (swap! a (fn [x] 
             (swap! a inc')
             (inc' x))))

我使用 inc' 这样它就真的永远存在了:它不会在 Long/MAX_VALUE 之后中断。

一种甚至不涉及另一个 swap! 操作的方法,更不用说另一个线程了!

(swap! (atom (repeat 1)) rest)

这里的问题是比较和交换中的 .equals 比较永远不会终止,因为 (repeat 1) 永远持续下去。

关于clojure - 如果线程在 `swap!` 期间更改原子的值会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68075869/

相关文章:

clojure - 将项目 -> 类别向量的 clojure 映射解析为分类列表

clojure - 翻译字符串的编码

clojure - 如何从 Clojure 中运行交互式 CLI 程序?

clojure - conda , condi , conde ,condu

jvm - 使用 Clojure/JVM 的守护进程

clojure - 为什么 clojure 的 group-by 不总是保持秩序?

debugging - 在 Clojure 中获取调用堆栈

clojure - Erlang 中的可变数据结构

clojure - 如何在 ClojureScript 中使用 `setTimeout`?

clojure - 为什么字符集看起来是有序的?