原文:https://doc.akka.io/docs/akka/2.5/general/jmm.htmlhtml
使用Lightbend平台(包括Scala和Akka)的一个主要好处是它简化了编写并发软件的过程。本文讨论Lightbend平台,特别是Akka如何在并发应用程序中使用共享内存。java
在Java 5以前,Java内存模型(JMM)定义不明确。当多个线程访问共享内存时,有可能得到各类奇怪的结果,例如:安全
随着Java 5中JSR 133的实现,不少这些问题都获得了解决。JMM是一组基于“happens-before”关系的规则,它限制一个存储器访问必须在另外一个存储器访问以前发生。这些规则的两个例子是:数据结构
尽管JMM看起来很复杂,但规范试图在易用性和编写高性能和可伸缩并发数据结构的能力之间找到平衡点。并发
使用Akka中的Actors实现,多个线程能够经过两种方式在共享内存上执行操做:app
为了防止Actor的可见性和从新排序问题,Akka保证如下两个“happens before”规则:post
这两个规则仅适用于同一个actor实例,若是使用不一样的actor,则无效。性能
若是您关闭引用,则还必须确保引用的实例是线程安全的。咱们强烈建议远离使用锁定的对象,由于它可能会致使性能问题,而且在最坏的状况下会致使死锁。这是同步的危险。this
因为Akka在JVM上运行,所以仍然须要遵循一些规则。spa
关闭内部Actor状态并将其暴露给其余线程
import akka.actor.{ Actor, ActorRef }
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.Future
import scala.concurrent.duration._
import scala.language.postfixOps
import scala.collection.mutablecase class Message(msg: String)
class EchoActor extends Actor {
def receive = {
case msg ⇒ sender() ! msg
}
}class CleanUpActor extends Actor {
def receive = {
case set: mutable.Set[_] ⇒ set.clear()
}
}class MyActor(echoActor: ActorRef, cleanUpActor: ActorRef) extends Actor {
var state = ""
val mySet = mutable.Set[String]()def expensiveCalculation(actorRef: ActorRef): String = {
// this is a very costly operation
"Meaning of life is 42"
}def expensiveCalculation(): String = {
// this is a very costly operation
"Meaning of life is 42"
}def receive = {
case _ ⇒
implicit val ec = context.dispatcher
implicit val timeout = Timeout(5 seconds) // needed for `?` below// Example of incorrect approach
// Very bad: shared mutable state will cause your
// application to break in weird ways
Future { state = "This will race" }
((echoActor ? Message("With this other one")).mapTo[Message])
.foreach { received ⇒ state = received.msg }// Very bad: shared mutable object allows
// the other actor to mutate your own state,
// or worse, you might get weird race conditions
cleanUpActor ! mySet// Very bad: "sender" changes for every message,
// shared mutable state bug
Future { expensiveCalculation(sender()) }// Example of correct approach
// Completely safe: "self" is OK to close over
// and it's an ActorRef, which is thread-safe
Future { expensiveCalculation() } foreach { self ! _ }// Completely safe: we close over a fixed value
// and it's an ActorRef, which is thread-safe
val currentSender = sender()
Future { expensiveCalculation(currentSender) }
}
}
//#mutable-state
}
消息应该是不可变的,这是为了不共享的可变状态陷阱。
原文:https://doc.akka.io/docs/akka/2.5/general/jmm.html