Akka学习笔记

本文深入探讨了Akka Actors模型的核心概念和技术细节,包括Actor的层次结构、生命周期管理、消息传递机制及失败处理策略等。此外,还介绍了如何利用Akka API进行Actor的创建与管理,以及如何实现Actor之间的交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

持续更新中….
目录

Akka官网

https://doc.akka.io/docs/akka/current/guide

Part 1 Actor结构

Actor的层次结构

这里写图片描述
所有的Actor都有一个父级Actor,system.actorOf()方法在/user目录下创建Actor,contextOf()方法在父级Actor下创建Actor。

Actor的生命周期

这里写图片描述
当一个actor被关闭时,它的所有子节点也将会被递归地关闭。这样可以很好的避免资源的浪费还有资源的泄露,例如当子节点中有一些打开的socket或者文件。事实上,在处理低层次的多线程代码时,一个通常被忽视的困难是各种并发资源的生命周期管理。

为了停止一个参与者,推荐的模式是调用getContext().stop(getSelf())在actor中停止自身,通常作为对某个用户定义的停止消息的响应,或者当参与者完成它的工作时。从技术上讲,通过调用getContext().stop(actorRef)来阻止另一个参与者是可行的,但是阻止任意的行为者被认为是一种不好的做法:尝试给他们发送一个PoisonPill或自定义的停止消息,让收到消息的Actor自己停止。

Akka actor API公开了许多可以在actor实现中覆盖的生命周期hooks。最常用的是preStart()和postStop()。

  • preStart():在Actor开始之后,处理第一条消息之前调用

  • postStop():在Actor停止之后条用,一旦调用,将不会处理任何消息

失败处理

一旦一个actor出错(抛出一个异常或者在receive方法中抛出)它会暂停,子级的错误会抛给父级,然后父级觉得如何处理异常,父级是作为子级的监视者,Akka提供的默认的监视策略是停止子级然后重启它。

Part 2 Actors

Actor模型对于高并发的分布式系统提供了更高层次的抽象。它让开发者可以避免显式的使用锁和管理线程,使得开发一个正确的并发系统更加容易。

创建Actors

定义一个Actor类

import akka.actor.AbstractActor;
import akka.event.Logging;
import akka.event.LoggingAdapter;

public class MyActor extends AbstractActor {
  private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);

  @Override
  public Receive createReceive() {
    return receiveBuilder()
      .match(String.class, s -> {
        log.info("Received String message: {}", s);
      })
      .matchAny(o -> log.info("received unknown message"))
      .build();
  }
}

Props

Props是一个配置类用于创建actor时提供具体的参数

import akka.actor.Props;
Props props1 = Props.create(MyActor.class);
Props props2 = Props.create(ActorWithArgs.class,
  () -> new ActorWithArgs("arg")); // careful, see below
Props props3 = Props.create(ActorWithArgs.class, "arg");

区别???待解决

使用Props创建Actors

通过将Props的实例传给ActorSystem或者ActorContext的工厂方法ActorOf来创建Actors。

import akka.actor.ActorRef;
import akka.actor.ActorSystem;
public class FirstActor extends AbstractActor {
  final ActorRef child = getContext().actorOf(Props.create(MyActor.class), "myChild");

  @Override
  public Receive createReceive() {
    return receiveBuilder()
      .matchAny(x -> getSender().tell(x, getSelf()))
      .build();
  }
}

调用actorOf方法返回的是ActorRef的实例,他是actor实例的引用,是唯一操作Actor的方法。

依赖注入

Inbox

Actor API

ActorSelection

Lifecycle Monitoring aka DeathWatch

为了在另一个Actor终止(即永久停止,而不是临时失败和重新启动)时被通知,Actor可以注册自己,以接收由另一个Actor在终止时发送的终止消息。该服务由actorSystem的DeathWatch组件提供。

import akka.actor.Terminated;
public class WatchActor extends AbstractActor {
  private final ActorRef child = getContext().actorOf(Props.empty(), "target");
  private ActorRef lastSender = system.deadLetters();

  public WatchActor() {
    getContext().watch(child); // <-- this is the only call needed for registration
  }

  @Override
  public Receive createReceive() {
    return receiveBuilder()
      .matchEquals("kill", s -> {
        getContext().stop(child);
        lastSender = getSender();
      })
      .match(Terminated.class, t -> t.actor().equals(child), t -> {
        lastSender.tell("finished", getSelf());
      })
      .build();
  }
}

也可以通过使用context.unwatch(target)来观察另一个Actor的活动轨迹。即使已终止的消息已经在邮箱中被排队,它也能正常工作;在调用unwatch后,将不再处理该actor的终止消息。

Identifying Actors via Actor Selection

消息和不变性(Immutability)

重要:消息可以是任何类型的对象,但是必须是不可变的,虽然Akka框架并没有在代码上强制要求。

发送消息

可以使用下面两个方法去发送消息:
- tell:是“fire-and-forget”模式,既异步的发送消息,然后立即返回
- ask:异步发送消息,然后返回一个代表返回值的Future对象

接收消息

接收超时时间

public class ReceiveTimeoutActor extends AbstractActor {
  public ReceiveTimeoutActor() {
    // To set an initial delay
    getContext().setReceiveTimeout(Duration.create(10, TimeUnit.SECONDS));
  }

  @Override
  public Receive createReceive() {
    return receiveBuilder()
      .matchEquals("Hello", s -> {
        // To set in a response to a message
        getContext().setReceiveTimeout(Duration.create(1, TimeUnit.SECONDS));
      })
      .match(ReceiveTimeout.class, r -> {
        // To turn it off
        getContext().setReceiveTimeout(Duration.Undefined());
      })
      .build();
  }
}

关闭Actor

import akka.actor.ActorRef;
import akka.actor.AbstractActor;

public class MyStoppingActor extends AbstractActor {

  ActorRef child = null;

  // ... creation of child ...

  @Override
  public Receive createReceive() {
    return receiveBuilder()
      .matchEquals("interrupt-child", m ->
        getContext().stop(child)
      )
      .matchEquals("done", m ->
        getContext().stop(getSelf())
      )
      .build();
  }
}

PoisonPill

你也可以发送一个akka.actor.PoisonPill。毒丸消息,当消息被处理时,它将停止Actor。毒丸作为普通消息排队,并将在邮箱中已经排队的消息后处理。

victim.tell(akka.actor.PoisonPill.getInstance(), ActorRef.noSender());

杀死Actor

你也可以发送一个Kill消息,它和毒丸消息不一样会抛出一个异常,这个Actor将会暂停操作,它的监视者将会被调用去处理这个异常,也许是恢复,重启或者完全关闭它。

victim.tell(akka.actor.Kill.getInstance(), ActorRef.noSender());

// expecting the actor to indeed terminate:
expectTerminated(Duration.create(3, TimeUnit.SECONDS), victim);

优雅的关闭

如果你需要等待终止或组合多个参与者的命令终止,那么gracefulStop方法是非常有用的。

try {
  CompletionStage<Boolean> stopped =
    gracefulStop(actorRef, Duration.create(5, TimeUnit.SECONDS), Manager.SHUTDOWN);
  stopped.toCompletableFuture().get(6, TimeUnit.SECONDS);
  // the actor has been stopped
} catch (AskTimeoutException e) {
  // the actor wasn't stopped within 5 seconds
}

Become/Unbecome

Stash

Part3 Dispatchers

Part4 Mailboxes

一个Akka的邮箱保存着相应Actor的消息,通常来说,每个Actor都有自己的邮箱,但是一个BalancingPool所有的路由都共享一个邮箱实例。

Mailbox Selection

Part5 Routes

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值