概述
本文主要介绍actor模型的定义和使用场景,最后介绍一个使用akka的例子。
actor模型定义
在许多并发场景中都会存在一些有状态的对象,并且存在多个线程访问并改变这些状态,通常情况下需要锁去控制访问。但是使用锁的话,每次只能有一个线程进行处理,性能很低。
如何避免锁?
上面是因为存在多个线程访问而导致竞争,如果我们设计专门的线程去维护这些状态,外部的线程只要把请求放入即可,这样就避免了竞争。而actor模型就是采用的相似的方式,每个actor都可以有行为和动作,底层有专门的线程运行, actor之间使用mailbox通信(类似消息队列)。
使用场景
何时适合使用actor模型?
- 对高并发有严格要求的同时又要维护某种状态
- 构建有限状态机,如果只是处理一个有限状态机,使用一个actor即可,如果是多个有限状态机,而且还要彼此交互,更应该选择actor模式
- 需要高并发,同时也需要很小心地管理并发
eg:需要确保特定的一组操作可以与系统中的某些操作并发运行,但不能与系统中其他操作并发运行
注意点
实现actor模型需要遵循以下规则:
- 所有的计算都是在actor中执行
- actor之间只能通过消息执行
- 为了响应消息,actor可以进行以下操作
(1)更改状态或行为
(2)发消息给其他actor
(3)创建有限数量的子actor
使用akka的例子
- 导入akka依赖
<!-- https://mvnrepository.com/artifact/com.typesafe.akka/akka-actor -->
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-actor_2.11</artifactId>
<version>2.4.9</version>
</dependency>
- 编写Greeter继承UntypedActor
public class Greeter extends UntypedActor{
public static enum Msg{
GREET,DONE;
}
@Override
public void onReceive(Object arg0) throws Throwable {
if(arg0==Msg.GREET){
System.err.println("Hello World");
getSender().tell(Msg.DONE, getSelf());
}else{
unhandled(arg0);
}
}
}
需要实现onReceive方法,根据收到的消息进行处理,上面代码如果收到的消息是Msg.GREET则返回Msg.DONE,否则不处理消息
- 编写HelloWorldActor
public class HelloWorld extends UntypedActor{
ActorRef greetor;
//preStart是生命周期函数,在actor启动时调用
@Override
public void preStart() throws Exception {
greetor = getContext().actorOf(Props.create(Greeter.class), "greetor");
System.err.println("Greetor Actor path:"+greetor.path());
//发送GREET消息
greetor.tell(Greeter.Msg.GREET, getSelf());
}
@Override
public void onReceive(Object msg) throws Throwable {
if(msg==Greeter.Msg.DONE){
//停止actor
getContext().stop(getSelf());
}else{
unhandled(msg);
}
}
}
- 编写main函数
public class HelloWorldSimpleMain {
public static void main(String[] args) {
ActorSystem system = ActorSystem.create("Hello", ConfigFactory.load("samplehello.conf"));
ActorRef a =system.actorOf(Props.create(HelloWorld.class),"helloworld");
System.err.println("HelloWorld path :"+a.path());
}
}
samplehello.conf配置了日志级别
akka{
loglevel = INFO
}
-
运行结果
小结
actor模型其实是更加面向对象的一种方式(OOP),actor对象有行为和数据,外部只要告诉actor消息,actor会根据自身状态选择合适的行为。在之前的编码中,我们都是通过类封装了数据和行为,并且向外部暴露这些行为,其实这样我们只是封装了数据但是使用时还要关注行为,与actor模型相比不够面向对象。