【问题标题】:Race conditions and clojure Atoms竞争条件和clojure Atoms
【发布时间】:2012-03-12 01:20:01
【问题描述】:

clojure“原子”的文档指出 -

"Changes to atoms are always free of race conditions."

然而,竞态条件的定义不仅仅是根据变化,而是在不同线程中并行逻辑操作的上下文中定义。

我想知道 - “对原子的更改总是不受竞争条件的影响”的保证有什么意义?在 java 中,我们有原子原语,它支持某些特定的线程安全操作(例如,AtomicInteger 支持“getAndIncrement”操作)。但是 Clojure 原子与类型无关,例如,我们可以调用:

  (atom "Hi im a string")  Or
  (atom (.getClass Object))

atom 方法的灵活性意味着 Clojure 在底层并不“聪明”地为 atom 提供特定于类型的原子/线程安全操作。

因此,我会问 - atom 方法究竟对我们的对象“做什么”(即它只是简单地同步整个对象吗?)

【问题讨论】:

    标签: java multithreading clojure atomic


    【解决方案1】:

    atom 实际上是一个保证线程安全的原子存储位置。

    Atom 类似于 Java 的 atomic 数据类型(如 AtomicReference),但实际上更强大,因为 atom 允许您使用任意函数来更新 atom。示例:

    (def a (atom "foo"))
    
    (defn appender [x]
      "Higher order function that returns a function which appends a specific string"
      (fn [s] 
        (str s x)))
    
    (swap! a (appender "bar"))
    => "foobar"
    

    在上面的例子中,swap! 操作的行为是原子的,即使我们传递给它的 appender 操作可能是一个非常复杂的函数。实际上,原子允许您以原子方式使用任意更新操作(您通常应该坚持使用纯函数,因为在发生争用时可能会多次调用该函数)。

    Atom 显然不能保证你放入其中的对象的线程安全(例如,如果你将一个未同步的 Java ArrayList 放入其中,那么它对于并发使用仍然是不安全的)。但是,如果您坚持使用 Clojure 的完全线程安全的不可变数据类型,那么您会很好。

    【讨论】:

    • “这些函数保证按顺序执行” - 这并不是atom 所保证的。实际保证是swap a f 记住a 的值,将其传递给f,如果f 完成后a 的值仍然等于旧值,则将其替换为f 的结果。同时,许多其他功能也可以应用于a,只要它们的效果相互抵消。
    • @Rafal - 谢谢好地方,我已经更新了答案,使其更加精确。
    • @myself:底层的比较实际上是 Java 的 ==(对象标识),所以我应该写“相同”而不是“相互抵消”->“离开”而不是“相等”引用同一个对象的原子”。
    • 哦,好吧....现在我明白为什么它被称为交换 -> 它假设修饰符具有准确的值的预表示。
    猜你喜欢
    • 1970-01-01
    • 2020-07-12
    • 2017-01-23
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 2018-10-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多