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

时间:2015-04-07 00:28:26

标签: scala akka

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

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

可以用更简单的方式在scala中完成线程安全的原子代码块吗?你会将@volatile应用于函数吗?

2 个答案:

答案 0 :(得分:4)

这取决于您希望在此处保护的共享状态:

  • 最简单和最普遍的选择是使用相同的旧synchronized。然而,与Akka不同,它完全阻挡,因此很容易扼杀你的表现,当然还有代码风格,因为很难控制混乱的副作用。它也可能允许dead-locks

  • Java locks采用相同的方法,但性能可能稍好一些。

  • 另一个选项是相同的旧Java AtomicReference(实现CAS操作)和相关类。积极的一点是它们是非阻塞的 - 开发人员实际上使用它们来构建高性能的集合。使用锁和CAS的方式被描述为here。它们都是相当低级别的机制,因此我不建议使用它们,特别是对于业务逻辑(任何演员的实现都会更好)。

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

  • Scala STM也是另类

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

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

答案 1 :(得分:2)

根据您要实现的目标,最简单的可能是旧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'的方式,但它可能对您有用,具体取决于您正在做什么。当然,如果您的同步操作更复杂和/或您需要高吞吐量,这是解决死锁的最快方法