在Akka官方文件中,他们不承认:
为了防止演员的可见性和重新排序问题,Akka保证以下两个“先发生”规则:
演员发送规则:发送消息给演员 在同一个演员收到该消息之前。演员 后续处理规则:处理一条消息之前发生 由同一个演员处理下一条消息。
请参阅the doc了解详情。
我想知道阿卡如何实现这个目标。我刚刚浏览了源代码(此时最新),我认为在执行Actor.receive
之前应该有一个Lock,但我没有找到任何锁(我认为)。最后,我找到了ActorCell.invoke
的评论:
//内存一致性由邮箱处理(读取邮箱 状态然后处理消息,然后写邮箱状态
是的,Mailbox.status
,我猜这就是我要找的。我看到他们使用Unsafe
来访问/更新status
字段,但我无法弄清楚如何确保内存可见性。
答案 0 :(得分:13)
要考虑两件事:传递消息并正确发布actor的内部状态。
前者是通过邮箱的MessageQueue实现实现的,它将使用volatile写入(对于默认的ConcurrentLinkedQueue)或锁(对于普通的LinkedBlockingQueue)来确保安排发布入队项。演员将通过读取相同的易失性字段(在第一种情况下)或采用相同的锁(在第二种情况下)与发送者同步,因此在消息发送之前的所有写入发生在演员处理该消息之前的任何内容之前
即使通过您找到的邮箱状态在另一个线程上重新安排了actor的内部状态,它也会安全地存放:处理一批消息(由throughput
参数定义)后,邮箱设置为“未调度”状态,这是一个易失性写入(实际上是Unsafe.compareAndSetInt()
,具有相同的语义)。在actor开始处理消息之前,它使用Unsafe.getIntVolatile
读取邮箱状态,该*Volatile
与前一次写入同步,因此在最后一批消息发生期间,所有写入操作都会发生 - 在此批次的所有读取之前。“ p>
您可以阅读有关所涉及操作的语义的更多信息here,请注意sun.misc.Unsafe
上的Atomic*Reference
方法遵循与{{1}}相同的规则。