Akka手册译(一)——Akka和Java内存模型

作者: 儿哥欠三百首 | 来源:发表于2017-01-01 22:43 被阅读0次

使用Lightbend平台的主要好处,包括Scala和Akka,它简化了编写并发软件的过程。本文讨论如何Lightbend平台,尤其是Akka,并发应用程序共享内存的方法。

Java内存模型

在Java 5之前,Java内存模型(JMM)有误的定义。由多个线程访问共享内存时可以得到各种奇怪的结果,如:

  • 线程看不到其它线程写入的值:可见性问题;
  • 线程观察其他线程的“不可能”行为,指令没有按预期的顺序执行引起:指令重新排序的问题。
    Java 5的JSR 133解决了这些问题。JMM的一组规则是基于“发生前”的关系,这强制了当一个内存访问发生在其它之前,相反地,允许在出现故障时发生。两个例子说明这些规则:
  • 监视锁规则:释放一个锁之前每一个后继得到相同的锁。
  • 易失变量规则:写易失性变量之前每一个后续的读相同的易失性变量。
    尽管JMM看起来复杂,规范试图找到一个易于使用和写的能力之间的平衡性能,可伸缩的并发数据结构。

Actor和Java内存模型

Akka中Actor的实现,有两种方法在共享内存环境下执行多线程行为:

  • 如果一个消息发送到一个Actor(如由另一个Actor)。在大多数情况下,消息是不可变的,但是如果这个信息构造不可变的对象是不正确的,没有“发生前”的规则,接收者可能部分初始化数据结构,甚至可能值是凭空捏造的(长型/双精度型)
  • 如果Actor在处理消息时改变内部状态,并在片刻后访问这个状态在处理另一个消息时。深刻认识到Actor模型中并不保证,同样的线程会对不同消息执行相同的Actor。
    为了避免Actor的可见性和重排序问题,Akka保证了下例两个“发生前”的规则:
  • Actor发送规则:一个Actor发送消息发生之前由通一个Actor接收消息。
  • Actor后续处理规则:在处理消息发生前由同一个Actor处理后续消息。

注意
通俗的讲改变Actor的内部字段在下一个消息的可见。Actor中的字段不能是易失或相价的。

两个规则仅适用于同一个Actor实例,对不同的Actor无效。

Futures和Java模型

完成Feature的“发生前”执行调用的回调注册。

我们建议不要封闭非final字段(在Java用final,在Scala中用val )如果你选择封闭非final字段,它们必须被标识为‘volatile’为了字段的当前值是可见的回调。

如果封闭一个引用,需要确保实例是线程安全的。我们强烈建议远离使用锁定的对象,因为它在最坏的情况下,引入性能问题和死锁。这样的同步是危险的。

Actor和共享可变状态

由于Akka运行在JVM上仍有一些规则要遵循。

  • 封闭Actor内部状态,并向其它线程暴露它。
1. class MyActor extends Actor {
2. var state = ...
3. def receive = {
4.    case _ =>
5.      //Wrongs
6. 
7.    // Very bad, shared mutable state,
8.    // will break your application in weird ways
9.      Future { state = NewState }
10.      anotherActor ? message onSuccess { r => state = r }
11. 
12.    // Very bad, "sender" changes for every message,
13.    // shared mutable state bug
14.      Future { expensiveCalculation(sender()) }
15. 
16.      //Rights
17. 
18.    // Completely safe, "self" is OK to close over
19.    // and it's an ActorRef, which is thread-safe
20.      Future { expensiveCalculation() } onComplete { f => self ! f.value.get }
21. 
22.    // Completely safe, we close over a fixed value
23.    // and it's an ActorRef, which is thread-safe
24.      val currentSender = sender()
25.      Future { expensiveCalculation(currentSender) }
26. }
27.}
  • 消息应该是不可变的,这是为了避免共享可变状态的陷阱。

上一篇
下一篇

相关文章

网友评论

    本文标题:Akka手册译(一)——Akka和Java内存模型

    本文链接:https://www.haomeiwen.com/subject/zteivttx.html