Java并发编程实战
王宝令
资深架构师
立即订阅
15151 人已学习
课程目录
已完结 50 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 你为什么需要学习并发编程?
免费
学习攻略 (1讲)
学习攻略 | 如何才能学好并发编程?
第一部分:并发理论基础 (13讲)
01 | 可见性、原子性和有序性问题:并发编程Bug的源头
02 | Java内存模型:看Java如何解决可见性和有序性问题
03 | 互斥锁(上):解决原子性问题
04 | 互斥锁(下):如何用一把锁保护多个资源?
05 | 一不小心就死锁了,怎么办?
06 | 用“等待-通知”机制优化循环等待
07 | 安全性、活跃性以及性能问题
08 | 管程:并发编程的万能钥匙
09 | Java线程(上):Java线程的生命周期
10 | Java线程(中):创建多少线程才是合适的?
11 | Java线程(下):为什么局部变量是线程安全的?
12 | 如何用面向对象思想写好并发程序?
13 | 理论基础模块热点问题答疑
第二部分:并发工具类 (14讲)
14 | Lock和Condition(上):隐藏在并发包中的管程
15 | Lock和Condition(下):Dubbo如何用管程实现异步转同步?
16 | Semaphore:如何快速实现一个限流器?
17 | ReadWriteLock:如何快速实现一个完备的缓存?
18 | StampedLock:有没有比读写锁更快的锁?
19 | CountDownLatch和CyclicBarrier:如何让多线程步调一致?
20 | 并发容器:都有哪些“坑”需要我们填?
21 | 原子类:无锁工具类的典范
22 | Executor与线程池:如何创建正确的线程池?
23 | Future:如何用多线程实现最优的“烧水泡茶”程序?
24 | CompletableFuture:异步编程没那么难
25 | CompletionService:如何批量执行异步任务?
26 | Fork/Join:单机版的MapReduce
27 | 并发工具类模块热点问题答疑
第三部分:并发设计模式 (10讲)
28 | Immutability模式:如何利用不变性解决并发问题?
29 | Copy-on-Write模式:不是延时策略的COW
30 | 线程本地存储模式:没有共享,就没有伤害
31 | Guarded Suspension模式:等待唤醒机制的规范实现
32 | Balking模式:再谈线程安全的单例模式
33 | Thread-Per-Message模式:最简单实用的分工方法
34 | Worker Thread模式:如何避免重复创建线程?
35 | 两阶段终止模式:如何优雅地终止线程?
36 | 生产者-消费者模式:用流水线思想提高效率
37 | 设计模式模块热点问题答疑
第四部分:案例分析 (4讲)
38 | 案例分析(一):高性能限流器Guava RateLimiter
39 | 案例分析(二):高性能网络应用框架Netty
40 | 案例分析(三):高性能队列Disruptor
41 | 案例分析(四):高性能数据库连接池HiKariCP
第五部分:其他并发模型 (4讲)
42 | Actor模型:面向对象原生的并发模型
43 | 软件事务内存:借鉴数据库的并发经验
44 | 协程:更轻量级的线程
45 | CSP模型:Golang的主力队员
结束语 (1讲)
结束语 | 十年之后,初心依旧
用户故事 (2讲)
用户来信 | 真好,面试考到这些并发编程,我都答对了!
3 个用户来信 | 打开一个新的并发世界
Java并发编程实战
登录|注册

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

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

用 STM 实现转账

我们曾经在《05 | 一不小心就死锁了,怎么办?》这篇文章中,讲到了并发转账的例子,示例代码如下。简单地使用 synchronized 将 transfer() 方法变成同步方法并不能解决并发问题,因为还存在死锁问题。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Java并发编程实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(13)

  • 我的腿腿
    我公司用的就是这个解决并发问题的,才知道是这种技术
    2019-06-06
    2
    7
  • M$画像
    希望王老师再出新品,一定支持。

    作者回复: 感谢捧场😄

    2019-06-24
    5
  • 照着实现了一遍,确实可以巧妙。
    我觉得类STMTxn的get函数可以改进一下:现在get返回的值,只是最初始的值,如果当前事务更改了值,然后再调用get,最好可以返回最新的值;即当前事务的更改,对自己是可见的。
    ```
        @Override
        public <T> T get(TxnRef<T> ref) {
            if (!inTxnMap.containsKey(ref)) {
                inTxnMap.put(ref, ref.curRef);
            }

            if (writeMap.containsKey(ref)) {
                return (T) writeMap.get(ref);
            }
            else {
                return (T) inTxnMap.get(ref).value;
            }
        }
    ```
    2019-08-19
    2
  • helloworld
    按照老师自己实现的STM程序,根本不存在commit提交失败的时候吧?因为每一次的commit都是新创建一个STMTxn,新创建STMTxn后,inTxnMap和writeMap都是新的。不知道我考虑的对不对??

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

    2019-09-23
    1
  • DFighting
    STM的优化有一点是针对大快照的优化吧,因为MySQL对数据库的快照并不是真正存储一份备份数据,类似例子中的map,而是利用version和undolog计算得到的,不然一个100G大小的数据库,每开启一个事物就拷贝一份数据,肯定是不现实的。
    2019-10-16
  • qpm
    谢谢老师推荐STM,我所在的游戏项目一直有对象异步入库的需求,为了使用异步入库,放弃了Spring针对数据库的事务。为此不得不编写大量代码去判断某个操作是否可以执行,希望软件事务内存可以为我的需求提供一个新的解决方案。最近几天开始研究相关源码了,希望可以较好的结合现有项目,有可以发布的成果一定在留言区为大家共享。

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

    2019-09-06
  • 悟空
    老师,private Map<TxnRef, VersionedRef> inTxnMap = new HashMap<>(); 这个是不是应该是静态的。在多个事物中共享,这样一个事物变更了,其他事物才能知晓
    2019-07-09
    1
  • Rancood
    感觉没有前面容易理解了
    2019-06-16
  • QQ怪
    哔,打卡,涨知识了
    2019-06-06
  • 有铭
    老师,关系数据库也是有死锁的,只是他们往往实现了死锁检测机制,死锁到一定时间就会强制解锁

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

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

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

    2019-06-06
  • 张三
    打卡!这篇高质量!
    2019-06-06
  • 爱吃回锅肉的瘦子
    涨见识了,谢谢老师。
    2019-06-06
收起评论
13
返回
顶部