《Java高并发程序设计》学习 --7.1 Akka之Hello World

45 篇文章 0 订阅
首先看一下,第一个Actor的实现:
public class Greeter extends UntypedActor {
	public static enum Msg {
		GREET,DONE;
	}
	@Override
	public void onReceive(Object msg) throws Exception {
		if(msg ==Msg.GREET) {
			System.out.println("Hello World!");
			getSender().tell(Msg.DONE, getSelf());
		} else 
			unhandled(msg);
	}
}
上述代码中,定义了一个欢迎者(Greeter)Actor,它继承自UntypedActor(Actor的核心成员)。UntypedActor就是我们所说的Actor,之所以这里是无类型的,因为在Akka中,还支持一种有类型的Actor。有类型的Actor可以使用系统中的其他类型构造,可以缓解Java单继承问题。
在这里,代码第2~4行,定义了消息类型。这里只有两种类型,欢迎(GREET)以及完成(DONE)。当Greeter收到GREET消息时,就会在控制台打印“Hello World”。并且向消息发送方发送DONE信息。
与Greeter交流的另外一个Actor是HelloWorld,它的实现如下:
public class HelloWorld extends UntypedActor {
	ActorRef greeter;
	@Override
	public void preStart() throws Exception {
		greeter = getContext().actorOf(Props.create(Greeter.class), "greeter");
		System.out.println("Greeter Actor Path:" + greeter.path());
		greeter.tell(Greeter.Msg.GREET, getSelf());
	}
	
	@Override
	public void onReceive(Object msg) throws Exception {
		if(msg == Greeter.Msg.DONE) {
			greeter.tell(Greeter.Msg.DONE, getSelf());
			getContext().stop(getSelf());
		} else 
			unhandled(msg);
	}
}
上述代码实现了一个名为HelloWorld的Actor。preStart()方法为Akka的回调方法,在Actor启动前,会被Akka框架调用,完成一些初始化工作。在这里,我们在HelloWorld中创建了Greeter的实例,并且向它发送GREET消息。此时,由于创建Greeter时使用的是HelloWorld的上下文,因此,它属于HelloWorld的子Actor。
onReceive()函数为HelloWorld的消息处理函数。在这里,只处理DONE的消息。在收到DONE消息后,它会向Greeter发送GREET消息,会打印两次“Hello World”。
主函数为:
public class HelloMainSimple {
	public static void main(String[] args) {
		Config config = ConfigFactory.load("samplehello.conf");
		ActorSystem system =   ActorSystem.create("Hello",ConfigFactory.load("samplehello.conf"));      			            			 				
		ActorRef a = system.actorOf(Props.create(HelloWorld.class), "helloWorld");
		System.out.println("HelloWorld Actor Path:" + a.path());
	}
}
程序第3行,创建了ActorSystem,表示管理和维护Actor的系统。一般来说,一个程序只需要一个ActorSystem就够用了。ActorSystem.create()的第1个参数“Hello”为系统名称,第2个参数为配置文件。
第4行通过ActorSystem创建一个顶级的Actor(HelloWorld)。
配置文件samplehello.conf的内容如下:
akka {
loglevel = INFO
}
在这里,只是简单地配置了一下日志级别为INFO。
执行上述代码,可以看到以下输出:

   
   
HelloWorld Actor Path:akka://Hello/user/helloWorld
Greeter Actor Path:akka://Hello/user/helloWorld/greeter
Hello World!
Hello World!
[INFO] [01/12/2017 15:46:01.303] [Hello-akka.actor.default-dispatcher-3] [akka://Hello/user/helloWorld] Message [cn.guet.parallel.akka.Greeter$Msg] from Actor[akka://Hello/user/helloWorld/greeter#-796575700] to Actor[akka://Hello/user/helloWorld#-605845893] was not delivered. [1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
第1行打印了HelloWorld Actor的路径。它是系统内第1个被创建的Actor。它的路径为:akka://Hello/user/helloWorld。其中第一个Hello表示ActorSystem的系统名,可以看一下我们构造ActorSystem时,传入的第1个参数就是Hello。接着user表示用户Actor。所有的用户Actor都会挂载在user这个路径下。第3个helloWorld就是这个Actor名字。
同理,第2个Greeter Actor的路径结构和HelloWorld是完全一致的。输出的第3、4行显示了Greeter打印的两条信息。第5行表示系统遇到了一条消息投递失败,失败的原因是HelloWorld将自己终止,导致Greeter发送的信息无法投递。
可以看到,当使用Actor进行并行程序开发时,我们的关注点已经不在线程上。实际上,线程调度已经被Akka框架进行封装,我们只需要关注Actor对象即可。而Actor对象之间的交流和普通的对象的函数调用有明显区别。它们是通过显示的消息发送来传递信息的。
当系统内有多个Actor存在时,Akka会自动在线程池中选择线程来执行Actor。因此,多个不同的Actor有可能会被同一个线程执行,同时,一个Actor也有可能被不同的线程执行。因此,一个值得注意的地方是:不要在一个Akka中执行耗时的代码,这样可能会导致其他Actor的调度出现问题。

注:本篇博客内容总结自《 Java 高并发程序设计》

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值