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并发编程实战
登录|注册

18 | StampedLock:有没有比读写锁更快的锁?

王宝令 2019-04-09
上一篇文章中,我们介绍了读写锁,学习完之后你应该已经知道“读写锁允许多个线程同时读共享变量,适用于读多写少的场景”。那在读多写少的场景中,还有没有更快的技术方案呢?还真有,Java 在 1.8 这个版本里,提供了一种叫 StampedLock 的锁,它的性能就比读写锁还要好。
下面我们就来介绍一下 StampedLock 的使用方法、内部工作原理以及在使用过程中需要注意的事项。

StampedLock 支持的三种锁模式

我们先来看看在使用上 StampedLock 和上一篇文章讲的 ReadWriteLock 有哪些区别。
ReadWriteLock 支持两种模式:一种是读锁,一种是写锁。而 StampedLock 支持三种模式,分别是:写锁悲观读锁乐观读。其中,写锁、悲观读锁的语义和 ReadWriteLock 的写锁、读锁的语义非常类似,允许多个线程同时获取悲观读锁,但是只允许一个线程获取写锁,写锁和悲观读锁是互斥的。不同的是:StampedLock 里的写锁和悲观读锁加锁成功之后,都会返回一个 stamp;然后解锁的时候,需要传入这个 stamp。相关的示例代码如下。
final StampedLock sl =
new StampedLock();
// 获取/释放悲观读锁示意代码
long stamp = sl.readLock();
try {
//省略业务相关代码
} finally {
sl.unlockRead(stamp);
}
// 获取/释放写锁示意代码
long stamp = sl.writeLock();
try {
//省略业务相关代码
} finally {
sl.unlockWrite(stamp);
}
StampedLock 的性能之所以比 ReadWriteLock 还要好,其关键是 StampedLock 支持乐观读的方式。ReadWriteLock 支持多个线程同时读,但是当多个线程同时读的时候,所有的写操作会被阻塞;而 StampedLock 提供的乐观读,是允许一个线程获取写锁的,也就是说不是所有的写操作都被阻塞。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Java并发编程实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(45)

  • linqw
    课后思考题:在锁升级成功的时候,最后没有释放最新的写锁,可以在if块的break上加个stamp=ws进行释放

    作者回复: 👍

    2019-04-09
    1
    32
  • 胡桥
    乐观锁的想法是“没事,肯定没被改过”,于是就开心地获取到数据,不放心吗?那就再验证一下,看看真的没被改过吧?这下可以放心使用数据了。
    我的问题是,验证完之后、使用数据之前,数据被其他线程改了怎么办?我看不出validate的意义。这个和数据库更新好像还不一样,数据库是在写的时候发现已经被其他人写了。这里validate之后也难免数据在进行业务计算之前已经被改掉了啊?

    作者回复: 改了就改了,读的数据是正确的一致的就可以了。如果这个规则不满足业务需求,可以总互斥锁。不同的锁用不同地方。

    2019-04-09
    1
    13
  • Presley
    老师,StampedLock 读模板,先通过乐观读或者悲观读锁获取变量,然后利用这些变量处理业务逻辑,会不会存在线程安全的情况呢? 比如,读出来的变量没问题,但是进行业务逻辑处理的时候,这时,读出的变量有可能发生变化了吧(比如被写锁改写了)?所以,当使用乐观读锁时,是不是等业务都处理完了(比如先利用变量把距离计算完),再判断变量是否被改写,如果没改写,直接return;如果已经改写,则使用悲观读锁做同样的事情。不过如果业务比较耗时,可能持有悲观锁的时间会比较长,不知道理解对不对

    作者回复: 两种场景,如果处理业务需要保持互斥,那么就用互斥锁,如果不需要保持互斥才可以用读写锁。一般来讲缓存是不需要保持互斥性的,能接受瞬间的不一致

    2019-04-09
    11
  • Grubby🐑
    bug是tryConvertToWriteLock返回的write stamp没有重新赋值给stamp

    作者回复: 👍

    2019-04-09
    1
    8
  • Grubby🐑
    老师,调用interrupt引起cpu飙高的原因是什么

    作者回复: 内部实现里while循环里面对中断的处理有点问题

    2019-04-09
    5
  • 发条橙子 。
    老师 , 我看事例里面成员变量都给了一个 final 关键字 。 请问这里给变量加 final的用意是什么 ,仅仅是为了防止下面方法中代码给他赋新的对象么 。 我在平常写代码中很少有给变量加 final 的习惯, 希望老师能指点一下 😄

    作者回复: 使用final是个好习惯

    2019-04-15
    1
    4
  • echo_陈
    以前看过java并发编程实战,讲jdk并发类库……不过那个书籍是jdk1.7版本……所以是头一次接触StempLock……涨知识了
    2019-04-09
    4
  • 冯传博
    解释一下 cpu 飙升的原因呗
    2019-04-09
    3
  • 密码123456
    悲观锁和乐观锁。悲观锁,就是普通的锁。乐观锁,就是无锁,仅增加一个版本号,在取完数据验证一下版本号。如果不一致那么就进行悲观锁获取锁。能够这么理解吗?
    2019-04-09
    3
  • ttang
    老师,ReadWriteLock锁和StampedLock锁都是可以同时读的,区别是StampedLock乐观读不加锁。那StampedLock比ReadWriteLock性能高的原因就是节省了加读锁的性能损耗吗?另外StampedLock用乐观读的时候是允许一个线程获取写锁的,是不是可以理解为StampedLock对写的性能更高,会不会因为写锁获取概率增大大,导致不能获取读锁。导致StampedLock读性能反而没有ReadWriteLock高?

    作者回复: 乐观读升级到悲观读,就和ReadWriteLock一样了。

    2019-04-10
    2
  • 疯狂咸鱼
    老师, if (ws != 0L)这个是判断是什么的?
    2019-07-17
    1
  • linqw
    从头重新看一篇,也自己大致写了下对StampedLock的源码分析https://juejin.im/editor/posts/5d00a6c8e51d45105d63a4ed,老师有空帮忙看下哦

    作者回复: 👍,有空我也学习一下😄

    2019-06-15
    1
  • 南北少卿
    jdk源码StampedLock中的示例,if (ws != 0L) 时使用了stamp=ws

    作者回复: 👍

    2019-05-12
    1
  • 狂风骤雨
    老师,你上章讲的ReadWriteLock,说的是当有一个线程在执行写操作时所有的读线程都被阻塞,本章你又提了一下ReadWriteLock,说的是当有多个线程进行读操作时,所有的写操作都被阻塞,这样是

    作者回复: 读写是互斥的

    2019-05-06
    1
  • ban
    老师,你好,
    如果我在前面long stamp = sl.readLock();升级锁后long ws = sl.tryConvertToWriteLock(stamp);
    这个 stamp和ws是什么关系来的,是sl.unlockRead(是关stamp还是ws)。两者有什么区别呢

    作者回复: stamp和ws没关系,tryConvertToWriteLock(stamp)这个方法内部会释放悲观读锁stamp(条件是能够升级成功)。所以我们需要释放的是ws

    2019-04-13
    1
  • 在distanceFromOrigin方法后面的部分,当判断完乐观锁没被修改过后就调用return Math.sqrt,感觉这里是一个check-than-act,不是原子的,会有线程安全问题,不知道我理解是否正确
    2019-11-04
  • 秋天
    使用 StampedLock 一定不要调用中断操作,如果需要...

    2019-10-22
  • ylw666
    老师好,对于数据库的乐观读锁的例子,虽然很巧妙,但有点疑问,除非应用场景是version不对就不允许update,如果应用场景只是互斥并发的update,我觉得应该利用数据库自身特性就足够,例如postgresql中update语句会锁表(http://www.postgres.cn/docs/10/explicit-locking.html#LOCKING-TABLES),不太需要您说的这个方法就可以实现并发的update。

    作者回复: 大部分问题数据库都能解决,解决不了的,基本上就开始体现程序员的价值了

    2019-10-10
  • Geek_00ce62
    tryConvertToWriteLock
    public long tryConvertToWriteLock(long stamp)
    If the lock state matches the given stamp, performs one of the following actions. If the stamp represents holding a write lock, returns it. Or, if a read lock, if the write lock is available, releases the read lock and returns a write stamp. Or, if an optimistic read, returns a write stamp only if immediately available. This method returns zero in all other cases.
    Parameters:
    stamp - a stamp
    Returns:
    a valid write stamp, or zero on failure
    2019-10-08
  • 业余草
    挺好的专栏,但是大多数人写业务逻辑用不到这些技术!

    作者回复: 技术只有在实践中才能锻炼出来,写业务逻辑的确机会很少

    2019-09-25
收起评论
45
返回
顶部