actor模型

概述

本文主要介绍actor模型的定义和使用场景,最后介绍一个使用akka的例子。

actor模型定义

在许多并发场景中都会存在一些有状态的对象,并且存在多个线程访问并改变这些状态,通常情况下需要锁去控制访问。但是使用锁的话,每次只能有一个线程进行处理,性能很低。
如何避免锁?
上面是因为存在多个线程访问而导致竞争,如果我们设计专门的线程去维护这些状态,外部的线程只要把请求放入即可,这样就避免了竞争。而actor模型就是采用的相似的方式,每个actor都可以有行为和动作,底层有专门的线程运行, actor之间使用mailbox通信(类似消息队列)。

使用场景

何时适合使用actor模型?

  1. 对高并发有严格要求的同时又要维护某种状态
  2. 构建有限状态机,如果只是处理一个有限状态机,使用一个actor即可,如果是多个有限状态机,而且还要彼此交互,更应该选择actor模式
  3. 需要高并发,同时也需要很小心地管理并发
    eg:需要确保特定的一组操作可以与系统中的某些操作并发运行,但不能与系统中其他操作并发运行

注意点

实现actor模型需要遵循以下规则:

  1. 所有的计算都是在actor中执行
  2. actor之间只能通过消息执行
  3. 为了响应消息,actor可以进行以下操作
    (1)更改状态或行为
    (2)发消息给其他actor
    (3)创建有限数量的子actor

使用akka的例子

  1. 导入akka依赖
    
        
            com.typesafe.akka
            akka-actor_2.11
            2.4.9
        
  1. 编写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,否则不处理消息

  1. 编写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);
        }
    }
}
  1. 编写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
}
  1. 运行结果


    运行结果.png

小结

actor模型其实是更加面向对象的一种方式(OOP),actor对象有行为和数据,外部只要告诉actor消息,actor会根据自身状态选择合适的行为。在之前的编码中,我们都是通过类封装了数据和行为,并且向外部暴露这些行为,其实这样我们只是封装了数据但是使用时还要关注行为,与actor模型相比不够面向对象。

你可能感兴趣的:(actor模型)