To prevent visibility and reordering problems on actors,Akka guarantees the following two “happens before” rules:
The actor send rule: the send of the message to an actor happens
before the receive of that message by the same actor. The actor
subsequent processing rule: processing of one message happens before
processing of the next message by the same actor.
详情请参考the doc.
我想知道Akka如何这样做.我刚刚通过源代码(最近在这一刻),我认为应该有一个Lock之前执行Actor.receive,但我没有找到任何锁(我想).最后,我发现ActorCell.invoke的评论:
//Memory consistency is handled by the MailBox (reading mailBox
status then processing messages,then writing mailBox status
是的,MailBox.status,我想这是我正在寻找的.我看到他们使用Unsafe访问/更新状态字段,但是我无法确定如何确保内存的可见性.
解决方法
前者通过邮箱的MessageQueue实现实现,该实现将使用易失性写入(默认ConcurrentLinkedQueue)或锁定(对于正常的LinkedBlockingQueue)来确保入队项目的安全发布.演员将通过读取相同的易失性字段(在第一种情况)或采取相同的锁(在第二种情况下)与发送方同步,因此在消息发送之前的所有写入发生在处理该消息之前的actor内的任何内容之前.
演员的内部状态被安全地收起,即使通过您发现的邮箱状态在不同的线程上重新安排:在处理一批消息(由吞吐量参数定义)后,邮箱设置为“未预定”状态,其中是一个易失性的写入(实际上是Unsafe.compareAndSetInt(),它具有相同的语义).在actor开始处理消息之前,它使用Unsafe.getIntVolatile(与之前的写入进行同步)来读取邮箱状态,因此在最后一批消息中,由actor完成的所有写入在此批次中的所有读取之前都会发生.
您可以阅读更多关于涉及的操作的语义here,请记住,sun.misc.Unsafe上的* Volatile方法遵循与Atomic * Reference相同的规则.