Akka简化了编写并发软件的过程,本文主要讨论Akka如何在并发应用中访问共享内存。
Java内存模型
Java5之前的JMM是相当混乱的。多线程访问共享内存很有可能会得奇怪的结果,如:
- 可见性问题,无法及时看到其他线程写入的值
- 指令乱序,观测到其他线程不可能的行为
从Java 5的JSR 133的实现,很多问题就解决了。JMM是基于一组"happens-before"关联规则,限制了访问内存的行为必须在另一个内存访问行为之前发生。当不想按顺序发生时,可以使用:
- 监视器锁规则:对一个锁的释放先于所有后续对同一个锁的获取
- volatile变量规则:对一个volatile变量的写操作先于所有后续对同一个volatile变量的读
JMM看起来很复杂,但是其规范试图在编写高性能,并发数据结构的能力间寻找平衡
Actor与Java内存模型
使用Akka的Actor,有两种方法可以使多线程操作共享内存:
- 假如一个message被发送给一个actor,在大多数情况下,message是不可变对象,万一message不是不可变的,没有”happen before"规则,receiver可能会看到部分初始化的数据,甚至可能看到无中生有的数据(long/double)
- 如果一个actor在处理消息时,改变了自己的内部状态,而后又在处理其他消息的时候访问了这个状态。我们需要知道的是,在使用Actor模型时,无法保证同一个线程在处理不同消息时,使用同一个actor(是指一个线程中有多个actor?还是一个actor改变了自己内部的状态后,就不是同一个actor?)
为了防止actor出现可见性问题,执行顺序问题,Akka制定了如下"happen before"规则:
- 发送规则:一条消息的发送动作先于同一个actor对同一条消息的接收
- actor后续处理规则:一条消息的处理,优先于同一个actor的下一条消息
两条规则只对同一个actor实例有效
通俗的解释:actor的内部变量(internal fields)是可见的,当下一个消息准备被处理时。所以你的actor的内部变量必须是volatile或者equivalent。
Futures与Java内存模型
一个Future的完成 “先于” 任何注册到它的回调函数的执行。
我们建议不要捕捉(close over)非final的值 (Java中称final,Scala中称val), 如果你 一定 要捕捉非final的值, 它们必须被标记为 volatile 来让它的当前值对回调代码可见。
如果你捕捉一个引用,, 你还必须保证它所指代的实例是线程安全的。 我们强烈建议远离使用锁的对象,因为它们会引入性能问题,甚至可能造成死锁。 这些是使用synchronized的风险。
STM与Java内存模型
Akka中的软件事务性内存 (STM) 也提供了一条 “发生在先” 规则:
- 事务性引用规则: 在提交过程中对一个事务性引用的成功的写操作先于所有对同一事务性引用的后续读操作发生。
这条规则非常象JMM中的 ‘volatile 变量’ 规则. 目前Akka STM只支持延迟写,所以对共享内存的实际写操作会被延迟到事务提交之时。事务中的写操作被存放在一个本地缓冲区中 (事务的写操作集) ,对其它的事务是不可见的。这就是为什么脏读是不可能的。
这些规则在Akka中的实现会随时间而变化,精确的细节甚至可能依赖于所使用的配置。但是它们是建立在其它的JMM规则如监视器锁规则和volatile变量规则基础上的。 这意味着Akka用户不需要操心为了提供“发生先于”关系而增加同步,因为这是Akka的工作。这样你可以腾出手来处理你的业务逻辑,让Akka框架来保证这些规则的满足。
Actors与共享的可变状态
由于Akka运行在JVM,有些规则仍然必须遵守
-
捕捉actor内部状态并暴露给其他线程
class MyActor extends Actor { var state = ... def receive = { case _ => //错误示范 // Very bad, 共享可变状态, // will break your application in weird ways Future { state = NewState } anotherActor ? message onSuccess { r => state = r } // Very bad, "sender" 随每个消息改变, //共享可变状态 bug Future { expensiveCalculation(sender()) } //正确示范 // Completely safe, "self" is OK to close over // and it's an ActorRef, which is thread-safe Future { expensiveCalculation() } onComplete { f => self ! f.value.get } // 非常安全,我们捕捉了一个固定值 // 并且它是一个Actor引用,是线程安全的 val currentSender = sender() Future { expensiveCalculation(currentSender) } } }
- 消息应该是不可变的,为了避免共享可变状态的陷阱
http://blog.csdn.net/wsscy2004/article/details/38421313
相关推荐
作为初学者,我发现将 Akka 与 Spring 的依赖注入集成有点复杂,尤其是在我使用 Java 时。 这个应用程序是向前迈出的一步,但以一种非常简单的方式(而不是使用 Spring Extension 和 ApplicationConfiguration 代码...
另外,本书介绍了 Actor 模型的一个实现框架 Akka 以及它的工具,而后讨论了在充分利用 actor 架构的基础上使用 Akka 框架来设计软件系统的方法,以及使用它来开发并发性和分布式应用程序的方怯。本书还介绍了领域 ...
在这里,您会喜欢三种含咖啡因的混合物之一: Akkaccino 、 MochaPlay和CaffeScala并在此过程中学习 Akka 和 Java 的基础知识。 为了实现这一点,您将完成一系列按主题组织的练习,这些练习在使用 Java 的 Akka ...
您将在Java和Scala中找到Akka的示例,同时讨论一个概念以及一个已解决的问题 ClientServerExample:此示例演示了远程参与者在客户端/服务器模式下的工作方式。 客户端将消息发送到服务器,服务器回复给客户端。 该...
akka实例 java实现tcp远程调用,一个服务端,一个客户端
This compact book includes in-depth introductions to RxJava, Akka Streams, and Reactor, and integrates the latest related features from Java 9 and 11, as well as reactive streams programming with the...
We believe that writing correct ...Please note that all code samples compile, so if you want direct access to the sources, have a look over at the Akka Docs subproject on github: for Java and Scala.
akka-study:akkaの勉强
scala-akka-study:scala-akka学习探索
带有 Maven、Spring Boot、Akka 和 Java 的微服务原型。 (来自: : ) 项目包含: TODO 接口结构 TODO 构建和运行 构建和运行: mvn clean package 然后像往常一样运行 JAR,如下所示: Unix nohup java ...
akka型团队:与Akka Typed,Akka Cluster Sharding和Cassandra结合在一起的未打磨宠物项目
基于Akka的高性能可伸缩的JAVA网络游戏服务器。简单的单服务器开发与集群开发的切换。使用Actor处理高并发。易于测试。服务的插件管理。高性能,可伸缩的Java Tcp服务器架构,1.Avalon基于Akka构建的服务器核心。...
akka-rabbitmq:Scala和Akka演员中的RabbitMq客户端
akka-microservice:具有Scala,Akka,Spray和CamelActiveMQ的微服务的示例
虽然与浏览器的交互当然也在范围内,但这并不是Akka HTTP的主要重点。 Akka HTTP遵循一个相当开放的设计,并且很多时候为“做同样的事情”提供了几种不同的API级别。 您将选择最适合您的应用程序的API抽象级别。 ...
AKKA (java) 精讲
Akka笔记 Akka消息 文档 源代码 从 Akka记录 文档 源代码 从 Akka测试 文档 源代码 从 Akka消息传递请求和响应 文档 源代码 从arunma / AkkaMessagingRequestResponse分叉
zio-akka-cluster:用于Akka群集的ZIO包装器
Akka ZIO应用 该项目的目的是将Akka Toolkit与ZIO一起使用,以构建高度并发,分布式和弹性消息驱动的应用程序 云 当地的 sbt run open http://0.0.0.0:8080