Actor之间发送消息,并不是直接通过API的方式直接实现,而是依赖于自己的邮箱(mailbox)。这就好比在旧社会中,大家进行信件交流,发件人把自己的信件放到自己的邮箱中,送件人每天早上从你的邮箱中取出信件,在这个过程中,邮箱就起到了中间存储作用,所有的信件都会放在里面。在Actor系统中,邮箱是一个队列结构,默认遵循FIFO,可以根据我们的需要自定义。
Actor可以接受其它多个Actor的消息,默认的消息顺序没有规律,无法保证某个消息一定排在另外一个消息的前面,但是对于同一个Actor发送的多个消息,一定是按照先后顺序接受。例如:actorA给ActorB发送message1和message2,那么ActorB接受消息的顺序一定是message1->message2,否则,执行任务岂不是乱套了。
邮箱的分类
在Akka中,邮箱主要分为两种类型:无界和有界。
类型 |
描述 |
无界(Unbounded) |
邮箱的容量没有上限,大部分无界邮箱都是无阻塞的。也就是说当消息的数量过于庞大时,也不会阻塞消息处理。 |
有界(Bounded) |
邮箱的容量有限制,当消息数量达到邮箱数量时,会根据mailbox-push-timeout-time(消息入队超时时间)的配置进行阻塞(或非阻塞),负数则表示无限超时(慎用)。 |
邮箱的配置
Akka系统中,提供了邮箱配置项,我们可以根据自己的需要进行配置,系统给我们提供了默认配置,例如:
akka.actor.default-mailbox{
mailbox-type="akka.dispatch.UnboundedMailbox"
mailbox-capacity=1000
mailbox-push-timeout-time=10s
}
参数分析:
mailbox-type:邮箱类型,默认采用无界邮箱UnboundedMailbox,表示邮箱队列大小不受限制。
mailbox-capacity:邮箱容量,定义有界邮箱(BoundedMail)的大小,该值只能为正数。
mailbox-push-timeout-time:入队超时时间,也就是消息进入队列的超时时限。
UnboundedMailbox主要依赖java.util.concurrent.ConcurrentLinkedQueue队列来实现,它是一个基于链表的队列结构,遵循FIFO,该队列结构采用CAS无锁算法保证多线程的安全,性能更佳(大家都懂得,锁会导致系统性能和吞吐量的下降,这里就不做过多介绍了)。
优先级邮箱
在实际的项目中,根据业务逻辑的需要,消息处理可能存在一定的优先级,那么我们就需要使用PriorityMailbox。下面我们就来看看优先级邮箱怎样使用:
目标:历史美女按照你喜欢的规则输出
第一步:extends PriorityMailbox,创建自己规则的优先级邮箱
public class PriorityMailbox extends UnboundedStablePriorityMailbox {
public PriorityMailbox(ActorSystem.Settings settings, Config config) {
super(new PriorityGenerator() {
//返回值越小,优先级越高
@Override
public int gen(Object message) {