Clojure
has an Atom for
changing state between threads in a synchronous and independent manner,that is not part of the STM.你
use it like this:
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是什么?
解决方法
正如@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
如果使用Scala-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(Boxed).