scala中的原子函数/方法(不引入actor系统开销)



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

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

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

这取决于您想要保护的共享状态类型:

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

  • Java的锁是相同的方法,但可能会在性能上稍微好一点。

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

  • 若您的共享状态是一个集合,那个么您可能希望使用相同的旧Java的并发集合(它们具有类似putIfAbscent的原子操作)。例如,Scala有有趣的非阻塞TrieMap。

  • Scala STM也是一种替代

  • 最后,这个问题专门讨论轻量级actor模型实现。

附言:Volatile注释不过是Java中的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 }

这是"旧Java"方式,但它可能对您有效,这取决于您正在做什么。当然,如果同步操作更复杂和/或需要高吞吐量,这是死锁的最快方法

最新更新