Java 并发编程实战
王宝令
资深架构师
72486 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 51 讲
学习攻略 (1讲)
Java 并发编程实战
15
15
1.0x
00:00/00:00
登录|注册

43 | 软件事务内存:借鉴数据库的并发经验

STM类
STMTxn类
TxnRef类
VersionedRef类
版本号的使用
数据库事务的快照
MVCC(Multi-Version Concurrency Control)
转账操作的示例
STM只支持ACI
持久性(Durability)
隔离性(Isolation)
一致性(Consistency)
原子性(Atomicity)
优化STM的方法
STM的适用范围
STM借鉴数据库的经验
STM主要在函数式语言中应用
I/O操作的难以支持回滚
自己实现STM
STM基于MVCC的实现
STM的简单使用
STM与数据库事务的对比
数据库事务的特性
总结
STM的局限性
STM的实现
借鉴数据库的并发经验
软件事务内存(STM)
软件事务内存(STM)知识关系脑图

该思维导图由 AI 生成,仅供参考

很多同学反馈说,工作了挺长时间但是没有机会接触并发编程,实际上我们天天都在写并发程序,只不过并发相关的问题都被类似 Tomcat 这样的 Web 服务器以及 MySQL 这样的数据库解决了。尤其是数据库,在解决并发问题方面,可谓成绩斐然,它的事务机制非常简单易用,能甩 Java 里面的锁、原子类十条街。技术无边界,很显然要借鉴一下。
其实很多编程语言都有从数据库的事务管理中获得灵感,并且总结出了一个新的并发解决方案:软件事务内存(Software Transactional Memory,简称 STM)。传统的数据库事务,支持 4 个特性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability),也就是大家常说的 ACID,STM 由于不涉及到持久化,所以只支持 ACI。
STM 的使用很简单,下面我们以经典的转账操作为例,看看用 STM 该如何实现。

用 STM 实现转账

我们曾经在《05 | 一不小心就死锁了,怎么办?》这篇文章中,讲到了并发转账的例子,示例代码如下。简单地使用 synchronized 将 transfer() 方法变成同步方法并不能解决并发问题,因为还存在死锁问题。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

软件事务内存(STM)是一种借鉴数据库并发经验的新型并发解决方案。文章首先指出,尽管许多开发者可能没有直接接触并发编程,但实际上在日常编程中,类似数据库和Web服务器已经解决了许多并发相关问题。STM受数据库事务管理的启发,通过实现原子性、一致性和隔离性来解决并发问题。相比传统的数据库事务,STM不涉及持久化,因此只支持ACI(原子性、一致性、隔离性)。 文章以转账操作为例,对比了使用数据库事务和STM的实现方式。在STM中,通过atomic()方法实现了并发问题的解决,相较于传统方法更为简单。STM的实现基于MVCC(多版本并发控制),类似于数据库事务的乐观锁。文章还介绍了如何自己实现STM,包括对数据的版本管理和事务的提交过程。 总的来说,STM借鉴了数据库的经验,但并非万能解决方案。目前主要应用于函数式编程语言,利用不可变性实现STM相对简单。文章最后提到了对STM实现的优化方法,并鼓励读者分享想法和思考。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Java 并发编程实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(26)

  • 最新
  • 精选
  • M$画像
    希望王老师再出新品,一定支持。

    作者回复: 感谢捧场😄

    2019-06-24
    22
  • 小文同学
    谢谢老师推荐STM,我所在的游戏项目一直有对象异步入库的需求,为了使用异步入库,放弃了Spring针对数据库的事务。为此不得不编写大量代码去判断某个操作是否可以执行,希望软件事务内存可以为我的需求提供一个新的解决方案。最近几天开始研究相关源码了,希望可以较好的结合现有项目,有可以发布的成果一定在留言区为大家共享。

    作者回复: 👍期待你的成果!

    2019-09-06
    9
    20
  • helloworld
    按照老师自己实现的STM程序,根本不存在commit提交失败的时候吧?因为每一次的commit都是新创建一个STMTxn,新创建STMTxn后,inTxnMap和writeMap都是新的。不知道我考虑的对不对??

    作者回复: 不是这样的,不同的STMTxn持有的TxnRef是共享的,TxnRef内部有版本号,主要依赖这个版本号来检测冲突

    2019-09-23
    4
    6
  • 黄海峰
    代码里硬是没看到哪里修改了version。。

    作者回复: 只创建新的版本,永远不会去修改

    2019-06-06
    2
  • Geek_039a5c
    代码还有有点小问题。 STM 这个类的代码 花括号写的不对。

    编辑回复: 收到,谢谢反馈,我和老师确认下

    2022-02-05
  • 石头汤
    是不是 STM.atomic 的 TxnRunnable 的实现必须是幂等的,否则 while 循环那里会产生脏数据?

    作者回复: 如果有冲突,写操作不会执行,所以不会产生脏数据

    2020-06-11
  • 纷繁的烟火
    最后段代码的 构造参数里的txn在哪呀 找也找不到

    作者回复: atomic方法内传入的,lambda表达式可以找专门的资料看看

    2020-01-14
  • 有铭
    老师,关系数据库也是有死锁的,只是他们往往实现了死锁检测机制,死锁到一定时间就会强制解锁

    作者回复: 当然有死锁,但是数据库的目标是努力消除他们,有些是数据库的bug,有些是我们没有用好

    2019-06-06
  • 松小鼠
    我公司用的就是这个解决并发问题的,才知道是这种技术
    2019-06-06
    5
    11
  • 小太阳
    看了三遍,终于看懂了,很妙。原来精华就在这一段:MVCC 可以简单地理解为数据库事务在开启的时候,会给数据库打一个快照,以后所有的读写都是基于这个快照的。当提交事务的时候,如果所有读写过的数据在该事务执行期间没有发生过变化,那么就可以提交;如果发生了变化,说明该事务和有其他事务读写的数据冲突了,这个时候是不可以提交的。Txn负责维护检测快照,TxnRef负责包装数据使之可以接入Txn,作为快照的key。VersionedRef负责包装数据使之有版本。 另外,最后的代码里忘了判断余额是否够用了。😁
    2020-07-08
    2
    10
收起评论
显示
设置
留言
26
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部