10

在官方的 Akka 文档中,他们否认:

为了防止 Actor 的可见性和重新排序问题,Akka 保证以下两个“发生在”规则:

演员发送规则:向演员发送消息发生在同一演员接收该消息之前。Actor 后续处理规则:一条消息的处理发生在同一 Actor 处理下一条消息之前。

请参考文档以获取详细信息。

我想知道 Akka 是如何做到这一点的。我刚刚浏览了源代码(此时最新),我认为在执行之前应该有一个 Lock Actor.receive,但我没有找到任何锁(我认为)。最后,我找到了一条评论ActorCell.invoke

//内存一致性由邮箱处理(先读邮箱状态再处理消息,再写邮箱状态

是的Mailbox.status,我想这就是我要找的。我看到他们Unsafe用来访问/更新该status字段,但我只是不知道这如何确保内存可见性。

4

1 回答 1

16

有两件事需要考虑:传递消息和正确发布actor的内部状态。

前者是通过邮箱的 MessageQueue 实现实现的,该实现将使用 volatile 写入(对于默认的 ConcurrentLinkedQueue)或锁(对于普通的 LinkedBlockingQueue)来确保入队项目的安全发布。Actor 将通过读取相同的 volatile 字段(在第一种情况下)或获取相同的锁(在第二种情况下)与发送方同步,因此在消息发送之前的所有写入都发生在处理该消息时 Actor 内的任何内容之前.

即使通过您找到的邮箱状态在不同的线程上重新安排了actor的内部状态,也可以安全地存放:处理一批消息(由throughput参数定义)后,邮箱设置为“未安排”状态,即一个 volatile 写(实际上Unsafe.compareAndSetInt(),它具有相同的语义)。在 Actor 开始处理消息之前,它使用 读取邮箱状态Unsafe.getIntVolatile,这与之前的写入同步,因此在最后一批消息期间 Actor 完成的所有写入都发生在该批次期间的所有读取之前。

您可以在此处阅读有关操作语义的更多信息,请记住*Volatileon 的方法sun.misc.Unsafe遵循与 for 相同的规则Atomic*Reference

于 2013-04-06T13:49:33.600 回答