Akka是什么
Akka是JAVA虚拟机平台上构建高并发、分布式和容错应用。Akka用Scala语言编写,同时提供了Scala和Java的开发接口。Akka处理并发的方法基于Actor模型,Actor之间通信的唯一机制就是消息传递
对并发模型进行了更高的抽象
Akka特点:
1.是异步(也可以做到同步)、非阻塞、高性能的事件驱动编程模型
2.是轻量级事件处理(1GB内存可容纳百万级别个Actor)
3.它提供了一种称为Actor的并发模型,其粒度比线程更小,你可以在系统中启用大量的Actor。
4.它提供了一套容错机制,允许在Actor出现异常时进行一些恢复或重置操作。
5.Akka既可以在单机上构建高并发程序,也可以在网络中构建分布式程序,并提供位置透明的Actor定位服务。
Actor是什么
Actor是由状态(state)、行为(behavior)、邮箱(mailbox)三者组成的。
1.状态(state):状态是指actor对象的变量信息,状态由actor自身管理,避免并发环境下的锁和内存原子性等问题。
2.行为(behavior):行为指定的是actor中计算逻辑,通过actor接收到的消息来改变actor的状态。
3.邮箱(mailbox):邮箱是actor之间的通信桥梁,邮箱内部通过FIFO消息队列来存储发送发消息,而接收方则从邮箱中获取消息。
看到一个比较好的介绍Actor模型:https://www.jianshu.com/p/d803e2a7de8e
Akka学习
1.引入maven
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-actor_2.13</artifactId>
<version>2.6.0</version>
</dependency>
2.HelloWorld案例
public class HelloWorld {
/**
* 定义一个actor,相当于是java中的继承Thread或者实现Runable接口
*/
static class ActorDemo extends AbstractActor {
//处理消息
@Override
public Receive createReceive() {
//处理一个具体类型的消息,比如是字符串类型的消息
Receive build = receiveBuilder().match(String.class,(msg)-> {
System.out.println(msg);
}).build();
return build;
}
}
public static void main(String[] args) {
//创建所有管理actor的系统管理对象
ActorSystem actorSystem = ActorSystem.create();
//通过这个系统管理对象创建actor,并返回当前actor的地址,可以理解成现实生活中用户的一个邮箱地址
ActorRef actorDemo = actorSystem.actorOf(Props.create(ActorDemo.class), "actorDemo");
//发送消息Object msg(发送消息的内容,任何类型的数据), final ActorRef sender(表示没有发送者(其实是一个叫做deadLetters的Actor))
actorDemo.tell("HelloWorld",ActorRef.noSender());
}
}
3.Actor消息转发
static class ActorDemo extends AbstractActor {
//处理消息
@Override
public Receive createReceive() {
//处理一个具体类型的消息,比如是字符串类型的消息
Receive build = receiveBuilder().match(String.class,(msg)-> {
System.out.println(msg);
//第一种方式
//getContext()上下文,可以理解成从从Actor管理系统中拿到指定的actor
ActorRef simpleActor = getContext().actorOf(Props.create(SimpleActorDemo.class), "simpleActor");
//发送者可以是任何Actor,getSelf()代表发送者是当前类ActorDemo
// simpleActor.tell("转发成功",getSelf());
//第二种方式,getContext()最开始发送的发送者Actor。比如有以下Actor,A>B>C,那么最开始发送的发送者Actor就是A
simpleActor.forward("forward方式,转发成功",getContext());
}).build();
return build;
}
}
static class SimpleActorDemo extends AbstractActor {
//处理消息
@Override
public Receive createReceive() {
//处理一个具体类型的消息,比如是字符串类型的消息
Receive build = receiveBuilder().match(String.class,(msg)-> {
System.out.println(msg);
}).build();
return build;
}
}
4.同步接收响应消息->future模式
akka中的future模式有两种,一种阻塞型,一种非阻塞型
阻塞:
Futuref= Patterns.ask(actor,msg,1500);
int re=(int)Await.result(f,timeout);
非阻塞:
Futuref= Patterns.ask(actor,msg,1500);
Patterns.pipe(f,system.dispatcher()).to(actor1)
//即将结果转移到另一个actor中进行处理
static class ActorDemo extends AbstractActor {
//处理消息
@Override
public Receive createReceive() {
//处理一个具体类型的消息,比如是字符串类型的消息
Receive build = receiveBuilder().match(String.class,(msg)-> {
System.out.println(msg);
//第一种方式
//getContext()上下文,可以理解成从从Actor管理系统中拿到指定的actor
ActorRef simpleActor = getContext().actorOf(Props.create(SimpleActorDemo.class), "simpleActor");
//发送者可以是任何Actor,getSelf()代表发送者是当前类ActorDemo
// simpleActor.tell("转发成功",getSelf());
//第二种方式,getContext()最开始发送的发送者Actor。比如有以下Actor,A>B>C,那么最开始发送的发送者Actor就是A
// simpleActor.forward("forward方式,转发成功",getContext());
getSender().tell("返回消息",getSelf());
}).build();
return build;
}
}
public static void main(String[] args) {
//创建所有管理actor的系统管理对象
ActorSystem actorSystem = ActorSystem.create();
//通过这个系统管理对象创建actor,并返回当前actor的地址,可以理解成现实生活中用户的一个邮箱地址
ActorRef actorDemo = actorSystem.actorOf(Props.create(ActorDemo.class), "actorDemo");
//发送消息Object msg(发送消息的内容,任何类型的数据), final ActorRef sender(表示没有发送者(其实是一个叫做deadLetters的Actor))
// actorDemo.tell("HelloWorld",ActorRef.noSender());
//设置一秒钟超时时间
Timeout timeout = new Timeout(Duration.create(1, TimeUnit.SECONDS));
Future future = Patterns.ask(actorDemo, "发送消息", timeout);
try {
// Await同步获取响应,如果超时了则会抛出java.util.concurrent.TimeoutException
Object result = Await.result(future, timeout.duration());
System.out.println(result.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
5.Actor 层次结构
/ 所谓的根监护人。这是系统中所有actor的父亲,当系统被终止时,它也是最后一个被停止的。
/user 这是所有用户创建的actor的父亲。不要被user这个名字所迷惑,他与最终用户没有关系,也和用户处理无关。你使用akka库所创建的所有actor的路径都将以/user/开头。
/system系统监护人。
context.actorOf()来创建新的非顶级actor,即子actor,context.actorOf()的方法和system.actorOf()相同。
public static void main(String[] args) {
//创建所有管理actor的系统管理对象
ActorSystem actorSystem = ActorSystem.create("actorSystem");
//通过这个系统管理对象创建actor,并返回当前actor的地址,可以理解成现实生活中用户的一个邮箱地址
ActorRef actorDemo1 = actorSystem.actorOf(Props.create(ActorDemo.class), "actorDemo1");
ActorRef actorDemo2 = actorSystem.actorOf(Props.create(ActorDemo.class), "actorDemo2");
System.out.println(actorDemo1);
System.out.println(actorDemo2);
}
两个路径都以akka://actorSystem/开头,所有的actor引用都是合法的URL。akka://是协议字段。
接下来,就像在World Wide Web上一样,URL是一个系统的标识。在这个示例里,系统的名称为actorSystem,它也可以被命名为任意名字。如果开启了多系统间的远程通信,URL里就会包含主机名,以便其他系统可以在网络上找到它。
在这个图片红色圈中的actorDemo1就是对应actorDemo1对象的actorSystem.actorOf中的name参数,而#后面的数字代表当前的Actor的id可以理解成邮箱地址并且是唯一性的。
6.Receive切换
/**
* Receive切换,不同的消息通过不同的Receive来处理
*/
static class becomeActorDemo extends AbstractActor {
private int count= 0;
@Override
public Receive createReceive() {
Receive receiveA = receiveBuilder().match(String.class,(msg)-> {
count++;
System.out.println("receiveA中count的值是:"+count);
if (msg.equals("3")) {
//如果msg等于3就切换到receiveB
getContext().become(receiveB);
}
}).build();
return receiveA;
}
Receive receiveC = receiveBuilder().match(String.class,(msg)-> {
count++;
System.out.println("receiveC中count的值是:"+count);
if (msg.equals("5")) {
//就切换回去到receiveA
getContext().unbecome();
}
}).build();
Receive receiveB = receiveBuilder().match(String.class,(msg)-> {
count++;
System.out.println("receiveB中count的值是:"+count);
if (msg.equals("4")) {
//切换到receiveC
getContext().become(receiveC);
}
}).build();
}
public static void main(String[] args) {
//创建所有管理actor的系统管理对象
ActorSystem actorSystem = ActorSystem.create("actorSystem");
//通过这个系统管理对象创建actor,并返回当前actor的地址,可以理解成现实生活中用户的一个邮箱地址
ActorRef becomeActorDemo = actorSystem.actorOf(Props.create(becomeActorDemo.class), "becomeActorDemo");
becomeActorDemo.tell("1",ActorRef.noSender());
becomeActorDemo.tell("2",ActorRef.noSender());
becomeActorDemo.tell("3",ActorRef.noSender());
becomeActorDemo.tell("4",ActorRef.noSender());
becomeActorDemo.tell("5",ActorRef.noSender());
becomeActorDemo.tell("6",ActorRef.noSender());
}
运行结果
Receive切换从receiveA>receiveB>receiveC,再到receiveA。
如果become方法的第二个参数默认是false
/**
* Receive切换,不同的消息通过不同的Receive来处理
*/
static class becomeActorDemo extends AbstractActor {
private int count= 0;
@Override
public Receive createReceive() {
Receive receiveA = receiveBuilder().match(String.class,(msg)-> {
count++;
System.out.println("receiveA中count的值是:"+count);
if (msg.equals("2")) {
//如果msg等于2就切换到receiveB
getContext().become(receiveB);
}
}).build();
return receiveA;
}
Receive receiveD = receiveBuilder().match(String.class,(msg)-> {
count++;
System.out.println("receiveD中count的值是:"+count);
if (msg.equals("5")) {
//就切换回去到receiveC
getContext().unbecome();
}
}).build();
Receive receiveC = receiveBuilder().match(String.class,(msg)-> {
count++;
System.out.println("receiveC中count的值是:"+count);
if (msg.equals("4")) {
//就到receiveD
getContext().become(receiveD,false);
}
}).build();
Receive receiveB = receiveBuilder().match(String.class,(msg)-> {
count++;
System.out.println("receiveB中count的值是:"+count);
if (msg.equals("3")) {
//切换到receiveC
getContext().become(receiveC);
}
}).build();
}
public static void main(String[] args) {
//创建所有管理actor的系统管理对象
ActorSystem actorSystem = ActorSystem.create("actorSystem");
//通过这个系统管理对象创建actor,并返回当前actor的地址,可以理解成现实生活中用户的一个邮箱地址
ActorRef becomeActorDemo = actorSystem.actorOf(Props.create(becomeActorDemo.class), "becomeActorDemo");
becomeActorDemo.tell("1",ActorRef.noSender());
becomeActorDemo.tell("2",ActorRef.noSender());
becomeActorDemo.tell("3",ActorRef.noSender());
becomeActorDemo.tell("4",ActorRef.noSender());
becomeActorDemo.tell("5",ActorRef.noSender());
becomeActorDemo.tell("6",ActorRef.noSender());
}
receiveA(become方法)>receiveB(become方法)>receiveC(become方法,false)>receiveD(unbecome)>receiveC
become方法的第二个参数默认是true,如果是false就会默认替换Receive为当前的正在处理消息的Receive,如果只有两个Receive时就算写了false但不会替换第一个Recevie也就是不会替换当前的receiveA。
7.Actor(生命周期)的停止,重启,恢复,启动
停止:
当actor被关闭后,其所有的子actor都将被递归地关闭
停止的方法有PoisonPill(不会向父节点发送异常消息),kill(会向父节点发送异常消息),stop