深入探索Akka演员模型:消息传递与协作实践
立即解锁
发布时间: 2025-08-19 02:34:06 阅读量: 4 订阅数: 34 


JVM并发编程的艺术与实践
### 深入探索Akka演员模型:消息传递与协作实践
#### 1. 好莱坞演员类的新特性
新版的`HollywoodActor`类在构造函数中接收一个`String`类型的`name`参数。在处理未识别的传入消息格式时,使用`case`语句来匹配消息的各种模式,而非`instanceof`。在Java中创建接受构造函数参数的演员较为复杂,但在Scala中却变得简单:
```scala
object UseHollywoodActor {
def main(args : Array[String]) : Unit = {
val tomHanks = Actor.actorOf(new HollywoodActor("Hanks")).start()
tomHanks ! "James Lovell"
tomHanks ! new StringBuilder("Politics")
tomHanks ! "Forrest Gump"
Thread.sleep(1000)
tomHanks.stop()
}
}
```
运行上述代码,输出如下:
```plaintext
Hanks playing James Lovell
Hanks plays no Politics
Hanks playing Forrest Gump
```
#### 2. 消息的发送与接收
可以向演员发送几乎任何类型的消息,如`String`、`Integer`、`Long`、`Double`、`List`、`Map`、元组、Scala的`case`类等,这些消息类型都是不可变的。
消息传递方式主要有以下两种:
- **单向消息传递**:“即发即忘”,使用`sendOneWay()`方法(Scala中使用`!`),发送是非阻塞的,调用者继续执行自己的工作。
- **双向消息传递**:发送消息并期望从演员处得到响应,调用线程会阻塞直到收到响应或超时。
##### 2.1 Java中的消息收发
以下是一个双向消息传递的示例:
```java
public class FortuneTeller extends UntypedActor {
public void onReceive(final Object name) {
getContext().replyUnsafe(String.format("%s you'll rock", name));
}
public static void main(final String[] args) {
final ActorRef fortuneTeller = Actors.actorOf(FortuneTeller.class).start();
try {
final Object response = fortuneTeller.sendRequestReply("Joe");
System.out.println(response);
} catch(ActorTimeoutException ex) {
System.out.println("Never got a response before timeout");
} finally {
fortuneTeller.stop();
}
}
}
```
为避免在没有阻塞发送者时`replyUnsafe()`方法失败,可以使用`replySafe()`方法:
```java
public class FortuneTeller extends UntypedActor {
public void onReceive(final Object name) {
if(getContext().replySafe(String.format("%s you'll rock", name)))
System.out.println("Message sent for " + name);
else
System.out.println("Sender not found for " + name);
}
public static void main(final String[] args) {
final ActorRef fortuneTeller = Actors.actorOf(FortuneTeller.class).start();
try {
fortuneTeller.sendOneWay("Bill");
final Object response = fortuneTeller.sendRequestReply("Joe");
System.out.println(response);
} catch(ActorTimeoutException ex) {
System.out.println("Never got a response before timeout");
} finally {
fortuneTeller.stop();
}
}
}
```
运行结果如下:
```plaintext
Sender not found for Bill
Message sent for Joe
Joe you'll rock
```
##### 2.2 Scala中的消息收发
Scala与Java的API存在一些差异:
- 可以直接使用`self`属性访问演员,调用`reply()`(不安全版本)或`replySafe()`方法。
- 可以使用`!!`代替`sendRequestReply()`,`!!!`代替`sendRequestReplyFuture()`。
- `sendRequestReply()`方法返回`Scala Option`,超时返回`None`,有响应返回`Some[T]`。
以下是使用不安全`reply()`方法的示例:
```scala
class FortuneTeller extends Actor {
def receive = {
case name : String =>
self.reply(String.format("%s you'll rock", name))
}
}
object FortuneTeller {
def main(args : Array[String]) : Unit = {
val fortuneTeller = Actor.actorOf[FortuneTeller].start()
val response = fortuneTeller !! "Joe"
response match {
case Some(responseMessage) => println(responseMessage)
case None => println("Never got a response before timeout")
}
fortuneTeller.stop()
}
}
```
使用安全版本的示例:
```scala
class FortuneTeller extends Actor {
def receive = {
case name : String =>
if(self.reply_?(String.format("%s you'll rock", name)))
println("Message sent for " + name)
else
println("Sender not found for " + name)
}
}
object FortuneTeller {
def main(args : Array[String]) : Unit = {
val fortuneTeller = Actor.actorOf[FortuneTeller].start()
fortuneTeller ! "Bill"
val response = fortuneTeller !! "Joe"
response match {
case Some(responseMessage) => println(responseMessage)
case None => println("Never got a response before timeout")
}
fortuneTeller.stop()
}
}
```
运行结果与Java版本相同:
```plaintext
Sender not found for Bill
Message sent for Joe
Joe you'll rock
```
#### 3. 多演员协作
以计算质数为例,展示多演员的协作。
##### 3.1 Java中的多演员协作
```java
public class Primes extends UntypedActor {
public void onReceive(final Object boundsList) {
final List<Integer> bounds = (List<Integer>) boundsList;
final int count = PrimeFinder.countPrimesInRange(bounds.get(0), bounds.get(1));
getContext().replySafe(count);
}
public static int countPrimes(
final int number, final int numberOfParts) {
final int chunksPerPartition = number / numberOfParts;
final List<Future<?>> results = new ArrayList<Future<?>>();
for(int index = 0; index < numberOf
```
0
0
复制全文
相关推荐









