scala 中的 Atomic function/method(不引入 actor 系统开销)

Atomic function/method in scala (without introducing actor system overheads)

我目前使用 Akka actor 来建立一个以线程安全方式原子执行的代码块(Akka 邮箱语义通过一次处理一条消息来强加原子性)。

然而,这引入了对 actor 系统的需求,以及额外的副作用或膨胀(必须手动将异常传播给调用者,在 ask 上失去类型安全,并且通常使用消息语义而不是函数调用)。

线程安全的原子代码块能否在scala中以更简单的方式实现?你会把 @volatile 应用于一个函数吗?

根据您要实现的目标,最简单的可能是旧的 synchronized

//your mutable state
 private var x = 0

//better than locking on 'this' is to have a dedicated lock
private val lock = new Object

def add(i:Int) = lock.synchronized { x += i }

这是 'old Java' 方式,但它可能适合您,具体取决于您正在做什么。当然,这是最快的死锁方法如果您的同步操作更复杂and/or您需要高吞吐量。

这取决于你想在这里保护什么样的共享状态:

  • 最简单和通用的选择是使用旧的 synchronized。然而,与 Akka 不同的是,它是完全阻塞的,因此可能很容易破坏你的性能,当然还有代码风格,因为它很难控制混乱的副作用。它还可能允许 dead-locks

  • Java的locks是相同的方法,但性能可能更好一些。

  • 另一个选项与旧 Java 的 AtomicReference(实现 CAS 操作)和相关 类 相同。积极的一面是它们是非阻塞的——开发人员实际上使用它们来构建高性能的集合。介绍了锁和CAS的使用方法here。它们都是非常低级的机制,所以我不建议过多使用它们,尤其是对于业务逻辑(任何参与者的实现都会更好)。

  • 如果你的共享状态是一个集合——你可能想使用旧的 Java 的并发集合(它们有像 putIfAbscent 这样的原子操作)。 Scala 有有趣的非阻塞 TrieMap 例如。

  • Scala STM也是备选

  • 最后,this question专用于轻量级actor模型实现。

P.S。易失性注解只不过是来自 Java 的 volatile 关键字模拟。你可以把它放在方法上,因为任何注释都可以放在任何东西上。