当前位置: 首页 > news >正文

软件事务内存导论(三)用Akka/Multiverse STM实现并发

用Akka/Multiverse STM实现并发

上面我们已经学习了如何在Clojure里使用STM,我猜你现在一定很好奇如何在Java代码中使用STM。而对于这一需求,我们有如下选择:

  • 直接在Java中使用Clojure STM。方法非常简单,我们只需将事务的代码封装在一个Callable接口的实现中就行了,详情请参见第7章。
  • 喜欢用注解(annotation)的开发者可能会更倾向于使用Multiverse的STM API.
  • 除了STM之外,如果我们计划使用角色(actor),那么还可以考虑选择Akka库。

Multiverse是由Peter Veentjer主持开发的一个基于Java的STM实现。通过这个库,我们可以在Java代码中使用注解来标识事务边界。我们既可以用@TransactionalMethod注解将单个的方法标记为事务性的,也可以用@TransactionalObject注解将一个类的所有方法都标记为事务性的。为了与其他JVM上的语言进行集成,Multiverse还提供了一组丰富的API来控制事物的开始和结束。

Akka是一个由Jonas Boner主持开发的一个基于Scala的解决方案,该方案可以用于包括Java在内的很多其他运行于JVM上的语言。Akka不但提供了STM和基于角色(actor)的并发方案,还提供了将二者混合使用的选项。此外,Akka使用Multiverse作为其STM的实现并提供了ACI(ACID的子集)特性。

Akka的性能非常棒,并且由于它既支持STM又支持基于角色(actor)的模型(详情请参见第8章),本章我们将会用它来实现演示Java STM的例子。


Akka/Multiverse中的事务

Akka的Java版采用了Multiverse的Clojure风格的STM。与Java那繁冗的代码风格相比,Clojure风格的Akka不会强迫我们在能够修改可变实体之前就创建事务。如果我们没有主动提供事务,则Akka/Multiverse就会自动把访问请求封装在一个事务中。所以当我们处于事务之中时,Akka的ref与Clojure的ref的表现是相同的;而当我们位于事务之外时,Akka ref的表现则更像是Clojure的atom。换句话说,想要使变更同步且有序就必须使其在事务中完成,否则变更将是同步但无序的。在任何情况下,Akka都会保证对于ref的更改是原子的、隔离的且一致的,并同时提供了不同等级的协调粒度。

在Akka中,我们既可以用写代码的方式在事务层对事务进行配置,也可以通过配置文件在应用程序/JVM层进行配置。例如,我们可以将一个事务定义为只读(readonly),于是Akka将不再允许任何位于该事务范围内的Akka引用被修改。这样做的好处是,如果我们将一些不可变的事务设置为只读,则程序性能将会得到一定的提升。除此之外,我们还可以控制在冲突情况下事务的最大重试次数。当然,还有很多其他参数可供我们配置,详情请参阅Akka的帮助文档。

Akka扩展了Multiverse中的嵌套事务(请参见6.9节),所以我们能够很方便地在事务中调用启动其他事务的函数。默认情况下,这些内部事务或嵌套事务都是与其外部事务融为一体的。

使用Akka引用和事务

Clojure中的ref是在语言层定义的,而 Akka是一个公共类库所以不能依赖任何现有语言的支持。所以Akka在其akka.stm包中提供了一个托管事务引用(managed transactional reference)Ref和一些为原始类型而设的特殊类,如IntRef、LongRef等。Ref(以及所有原始类型的特化引用)代表指向类型T的一个不可变值的托管可变实体(managed mutable identity)。像Integer、Long、Double、String这些类型以及其他不可变类型都符合作为值对象的(value object)条件。如果我们用了自己定义的类,则必须保证这个类是不可变的。也就是说,这个自定义的类只能包含final字段。

我们可以创建一个Ref的实例作为托管事务引用,其值可以在初始化时指定或干脆不指定(默认为null)。如果想获得引用的当前值,可以使用get()函数。如果要使引用指向另一个可变实体,则可以使用swap()函数。这些调用可以在我们提供的事务里执行,但如果我们没提供事务的话,它们也可以在其各自的事务中运行。

当多个线程都试图更改同一个托管引用时,Akka可以保证只有一个变更可以写入内存而其他变更将全部重做。Akka有专门的事务工具负责管理事务跨越内存栅栏的过程。也就是说,Akka(通过Multiverse)保证了在事务中一个托管ref变更的提交会先于后续所有其他事务对该ref的读操作,即该变更对所有其他事务可见。 

相关文章:

  • 本地jar安装到maven仓库 和 ivy仓库方法
  • XUL 用户界面语言介绍
  • Reddit引入Envoy支持架构改造,性能显著提升
  • 弄懂Favicon
  • 基于django的视频点播网站开发-step15-项目部署
  • php任务队列
  • OpsRamp推出以服务为中心的AIOps和云监控功能
  • C# 如何在Excel 动态生成PivotTable
  • 08.Android之View事件问题
  • .naturalWidth 和naturalHeight属性,
  • 数据模型
  • 深度解析利用ES6进行Promise封装总结
  • 上传本地项目到git.oschina
  • ES6系统学习----从Apollo Client看解构赋值
  • 前端临床手札——文件上传
  • [译]前端离线指南(上)
  • 【Linux系统编程】快速查找errno错误码信息
  • 08.Android之View事件问题
  • Android交互
  • ES学习笔记(10)--ES6中的函数和数组补漏
  • HashMap剖析之内部结构
  • Java 最常见的 200+ 面试题:面试必备
  • JavaScript 奇技淫巧
  • JS学习笔记——闭包
  • Logstash 参考指南(目录)
  • PHP变量
  • Python 反序列化安全问题(二)
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • 前端每日实战 2018 年 7 月份项目汇总(共 29 个项目)
  • 设计模式(12)迭代器模式(讲解+应用)
  • 使用common-codec进行md5加密
  • 微信开源mars源码分析1—上层samples分析
  • Java数据解析之JSON
  • Salesforce和SAP Netweaver里数据库表的元数据设计
  • ​sqlite3 --- SQLite 数据库 DB-API 2.0 接口模块​
  • ( 用例图)定义了系统的功能需求,它是从系统的外部看系统功能,并不描述系统内部对功能的具体实现
  • (14)Hive调优——合并小文件
  • (16)UiBot:智能化软件机器人(以头歌抓取课程数据为例)
  • (4)事件处理——(7)简单事件(Simple events)
  • (DFS + 剪枝)【洛谷P1731】 [NOI1999] 生日蛋糕
  • (第61天)多租户架构(CDB/PDB)
  • (附源码)spring boot基于小程序酒店疫情系统 毕业设计 091931
  • (蓝桥杯每日一题)love
  • (蓝桥杯每日一题)平方末尾及补充(常用的字符串函数功能)
  • (力扣记录)1448. 统计二叉树中好节点的数目
  • (六)vue-router+UI组件库
  • (十五)Flask覆写wsgi_app函数实现自定义中间件
  • (一)kafka实战——kafka源码编译启动
  • (一)Linux+Windows下安装ffmpeg
  • (转)可以带来幸福的一本书
  • ../depcomp: line 571: exec: g++: not found
  • ./include/caffe/util/cudnn.hpp: In function ‘const char* cudnnGetErrorString(cudnnStatus_t)’: ./incl
  • .net 桌面开发 运行一阵子就自动关闭_聊城旋转门家用价格大约是多少,全自动旋转门,期待合作...
  • .NET/C# 解压 Zip 文件时出现异常:System.IO.InvalidDataException: 找不到中央目录结尾记录。
  • .NET开发者必备的11款免费工具