Akka之HelloWorld

UntypedActor就是我们所说的Actor,之所以这里强调是无类型的,那是因为在Akka中,还支持一种有类型的Actor。有类型的Actor可以使用系统中的其他类型构造,可以缓解Java单继承的问题。因为你在继承了UntypedActor后,就不能再继承系统中的其他类了。如果你一定想这么做,那么就只能选择有类型的Actor。否则,UntypedActor应该就是你的首选。

  • unhandle(msg) 不处理消息
  • getSender() 获取发送者
  • getSelf() 获取自身角色
  • getSender().tell(msg, getSelf()) 向发送者回复消息

    实例

    public class HelloWorld extends UntypedActor {
    
        ActorRef greeter;
    
        // Akka的回调方法,在Actor启动前会被Akka框架调用,完成一些初始化的工作
        @Override
        public void preStart() throws Exception {
    
            // 获取当前上下文
            UntypedActorContext untypedActorContext = getContext();
    
            // 创建Greenter的实例,有当前上下文创建,所以是HelloWorld的子Actor
            greeter = untypedActorContext.actorOf(Props.create(Greeter.class), "greeter");
    
            greeter.tell(Greeter.Msg.GREET, getSelf());
    
        }
    
        // 消息处理函数
        @Override
        public void onReceive(Object msg) throws Exception {
            if (msg == Greeter.Msg.DONE) {
                // 回复欢迎消息,并停止自己
                greeter.tell(Greeter.Msg.GREET, getSelf());
    
                // 停止自己
                getContext().stop(getSelf());
            } else {
                unhandled(msg);
            }
        }
    }

    ActorSystem表示管理和维护Actor的系统。一般来说,一个应用程序只需要有一个ActorSystem就够了。

public static akka.actor.ActorSystem create(java.lang.String s, com.typesafe.config.Config config):
第一个参数s为系统名称,第二个参数config为配置文件。

ActorSystem system = ActorSystem.create("Hello", ConfigFactory.load("samplehello.conf"));
// 顶级的Actor,由系统创建
ActorRef actorRef = system.actorOf(Props.create(HelloWorld.class), "helloWorld");
System.out.println("HelloWorld Actor Path:" + actorRef.path());

akka{
    loglevel = INFO // 日志级别
}

Actor的路径akka://Hello/user/helloWorld,第一个Hello表示系统名,user表示用户Actor,所有的用户Actor都会挂载到user这个用户路径下,helloWorld就是这个Actor的名字。

Akka将线程的调度进行封装,使我们只需要关注Actor对象就可以了。当系统内存在多个Actor时,Akka会在线程池中选择线程来执行我们的Actor。因此,多个不同的Actor可能被同一个线程执行,也可能被多个线程执行。
需要注意的是:我们不要在Actor中执行耗时的任务,这可能会影响到其他Actor的执行。


消息投递的说明

Akka的核心组件包括Actor和消息。

消息应该满足不变性,因为可变的消息无法高效的并发环境中使用。理论上Akka的消息可以任何对象,但是推荐使用不变对象,如下:

public final class ImmutableMesssage { // final不可继承,防止被子类破坏
    private final int sequenceNumber;
    private final List<String> values;

    public ImmutableMesssage(int sequenceNumber, List<String> values) {
        this.sequenceNumber = sequenceNumber;
        this.values = Collections.unmodifiableList(new ArrayList<>(values)); // fianl仅表示引用不可变,构造不可变的list
    }

    public int getSequenceNumber() {

        return sequenceNumber;
    }

    public List<String> getValues() {
        return values;
    }
}

投递消息的策略

  1. 至多一次投递。每条消息最多投递一次。在这种情况下,会偶尔出现消息投递失败的情况,从而导致消息丢失。最低成本,最高性能,但会丢失消息,因为系统只要把消息投递出去就行了,不关注是否会成功。
  2. 至少一次投递。每条消息至少会被投递一次,直到成功为止。因此在一下偶然的场合,接受者可能会收到重复的消息,但是消息不会丢失。需要保证消息的状态并不断重试,会出现重复投递的情况。
  3. 精确的消息投递。保证消息被精确的投递成功且只接受一次,即不会丢失,也不会重复接受。成本最高,最不容易实现。
    可靠的消息投递有时候是没必要的,成本太高了,我们应该在应用的业务层去保证。

消息投递的顺序

只保证一定程度上的顺序性,来自同一个Actor的消息是有先后顺序的,不同的Acotr的消息则可能交织在一起。不具备传递性。如:Actor A1向A2顺序发送了M1、M2和M3三条消息。Actor A3向A2顺序发送了M4、M5和M6三条消息。那么系统可以保证:
1. 如果M1没有丢失,那它一定先于M2和M3被A2收到。
2. 如果M2没有丢失,那它一定先于M3被A2收到。
3. 如果M4没有丢失,那它一定先于M5和M6被A2收到。
4. 如果M5没有丢失,那它一定先于M6被A2收到。
5. 对A2来说,来自A1和A3的消息可能交织在一起,没有顺序保证。
在这里,值得注意的一点是,这种消息投递规则不具备可传递性,比如:Actor A向C发送了M1,接着,Actor A向B发送了M2,B将M2转发给Actor C。那么在这种情况下,C收到M1和M2的先后顺序是没有保证的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值