问题 什么是Scala相当于Clojure的Atom?


Clojure的 有一个原子 对于 以同步和独立的方式改变线程之间的状态这不是STM的一部分。您 像这样使用它

user=> (def my-atom (atom 0))
#'user/my-atom

user=> @my-atom
0

user=> (swap! my-atom inc)
1

user=> @my-atom
1

user=> (swap! my-atom (fn [n] (* (+ n n) 2)))
4

我的问题是: 什么是Scala相当于Clojure的Atom?


1174
2018-02-16 01:24


起源



答案:


正如@Shepmaster和@ om-nom-nom所说,它是一个包装器 java.util.concurrent.atomic.Atomic...

等效的包装器可能如下所示:

import java.util.concurrent.atomic._
import scala.annotation.tailrec

object Atom {
  def apply[A](init: A): Atom[A] = new Impl(new AtomicReference(init))

  private class Impl[A](state: AtomicReference[A]) extends Atom[A] {
    def apply(): A = state.get()
    def update(value: A): Unit = state.set(value)
    def transformAndGet(f: A => A): A = transformImpl(f)

    @tailrec private final def transformImpl(fun: A => A): A = {
      val v    = state.get()
      val newv = fun(v)
      if (state.compareAndSet(v, newv)) newv
      else transformImpl(fun)
    }
  }
}
trait Atom[A] {
  def apply(): A
  def update(value: A): Unit
  def transformAndGet(f: A => A): A
}

例如:

val myAtom = Atom(0)
myAtom()  // --> 0
myAtom.transformAndGet(_ + 1) // --> 1
myAtom()  // --> 1
myAtom.transformAndGet(_ * 4) // --> 4

如果你使用 斯卡拉-STM,通过使用,该功能内置于STM引用中 .single 视图:

scala> import scala.concurrent.stm._
import scala.concurrent.stm._

scala> val myAtom = Ref(0).single
myAtom: scala.concurrent.stm.Ref.View[Int] = 
        scala.concurrent.stm.ccstm.CCSTMRefs$IntRef@52f463b0

scala> myAtom()
res0: Int = 0

scala> myAtom.transformAndGet(_ + 1)
res1: Int = 1

scala> myAtom()
res2: Int = 1

scala> myAtom.transformAndGet(_ * 4)
res3: Int = 4

优点是 Ref.apply 将为您提供原始类型的专用单元格,例如: Int 代替 AnyRef (盒装)。


8
2018-02-16 10:17



这是一个与Clojure相匹配的Scala实现,包括手表支持: gist.github.com/kirked/32ed1773363dc9b9fb507bc8a07a4db4 - WeaponsGrade


答案:


正如@Shepmaster和@ om-nom-nom所说,它是一个包装器 java.util.concurrent.atomic.Atomic...

等效的包装器可能如下所示:

import java.util.concurrent.atomic._
import scala.annotation.tailrec

object Atom {
  def apply[A](init: A): Atom[A] = new Impl(new AtomicReference(init))

  private class Impl[A](state: AtomicReference[A]) extends Atom[A] {
    def apply(): A = state.get()
    def update(value: A): Unit = state.set(value)
    def transformAndGet(f: A => A): A = transformImpl(f)

    @tailrec private final def transformImpl(fun: A => A): A = {
      val v    = state.get()
      val newv = fun(v)
      if (state.compareAndSet(v, newv)) newv
      else transformImpl(fun)
    }
  }
}
trait Atom[A] {
  def apply(): A
  def update(value: A): Unit
  def transformAndGet(f: A => A): A
}

例如:

val myAtom = Atom(0)
myAtom()  // --> 0
myAtom.transformAndGet(_ + 1) // --> 1
myAtom()  // --> 1
myAtom.transformAndGet(_ * 4) // --> 4

如果你使用 斯卡拉-STM,通过使用,该功能内置于STM引用中 .single 视图:

scala> import scala.concurrent.stm._
import scala.concurrent.stm._

scala> val myAtom = Ref(0).single
myAtom: scala.concurrent.stm.Ref.View[Int] = 
        scala.concurrent.stm.ccstm.CCSTMRefs$IntRef@52f463b0

scala> myAtom()
res0: Int = 0

scala> myAtom.transformAndGet(_ + 1)
res1: Int = 1

scala> myAtom()
res2: Int = 1

scala> myAtom.transformAndGet(_ * 4)
res3: Int = 4

优点是 Ref.apply 将为您提供原始类型的专用单元格,例如: Int 代替 AnyRef (盒装)。


8
2018-02-16 10:17



这是一个与Clojure相匹配的Scala实现,包括手表支持: gist.github.com/kirked/32ed1773363dc9b9fb507bc8a07a4db4 - WeaponsGrade


这不是Scala特有的,但我会伸手去拿 的AtomicReference 首先在Java土地上。多少钱 atom您想要/需要的功能吗?


5
2018-02-16 03:37



顺便一提 原子是在原子参考的顶部实现的 - om-nom-nom