Java性能调优实战
刘超
金山软件西山居技术经理
立即订阅
7535 人已学习
课程目录
已完结 48 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 怎样才能做好性能调优?
免费
模块一 · 概述 (2讲)
01 | 如何制定性能调优标准?
02 | 如何制定性能调优策略?
模块二 · Java编程性能调优 (10讲)
03 | 字符串性能优化不容小觑,百M内存轻松存储几十G数据
04 | 慎重使用正则表达式
05 | ArrayList还是LinkedList?使用不当性能差千倍
加餐 | 推荐几款常用的性能测试工具
06 | Stream如何提高遍历集合效率?
07 | 深入浅出HashMap的设计与优化
08 | 网络通信优化之I/O模型:如何解决高并发下I/O瓶颈?
09 | 网络通信优化之序列化:避免使用Java序列化
10 | 网络通信优化之通信协议:如何优化RPC网络通信?
11 | 答疑课堂:深入了解NIO的优化实现原理
模块三 · 多线程性能调优 (10讲)
12 | 多线程之锁优化(上):深入了解Synchronized同步锁的优化方法
13 | 多线程之锁优化(中):深入了解Lock同步锁的优化方法
14 | 多线程之锁优化(下):使用乐观锁优化并行操作
15 | 多线程调优(上):哪些操作导致了上下文切换?
16 | 多线程调优(下):如何优化多线程上下文切换?
17 | 并发容器的使用:识别不同场景下最优容器
18 | 如何设置线程池大小?
19 | 如何用协程来优化多线程业务?
20 | 答疑课堂:模块三热点问题解答
加餐 | 什么是数据的强、弱一致性?
模块四 · JVM性能监测及调优 (6讲)
21 | 磨刀不误砍柴工:欲知JVM调优先了解JVM内存模型
22 | 深入JVM即时编译器JIT,优化Java编译
23 | 如何优化垃圾回收机制?
24 | 如何优化JVM内存分配?
25 | 内存持续上升,我该如何排查问题?
26 | 答疑课堂:模块四热点问题解答
模块五 · 设计模式调优 (6讲)
27 | 单例模式:如何创建单一对象优化系统性能?
28 | 原型模式与享元模式:提升系统性能的利器
29 | 如何使用设计模式优化并发编程?
30 | 生产者消费者模式:电商库存设计优化
31 | 装饰器模式:如何优化电商系统中复杂的商品价格策略?
32 | 答疑课堂:模块五思考题集锦
模块六 · 数据库性能调优 (8讲)
33 | MySQL调优之SQL语句:如何写出高性能SQL语句?
34 | MySQL调优之事务:高并发场景下的数据库事务调优
35 | MySQL调优之索引:索引的失效与优化
36 | 记一次线上SQL死锁事故:如何避免死锁?
37 | 什么时候需要分表分库?
38 | 电商系统表设计优化案例分析
39 | 数据库参数设置优化,失之毫厘差之千里
40 | 答疑课堂:MySQL中InnoDB的知识点串讲
模块七 · 实战演练场 (4讲)
41 | 如何设计更优的分布式锁?
42 | 电商系统的分布式事务调优
43 | 如何使用缓存优化系统性能?
44 | 记一次双十一抢购性能瓶颈调优
结束语 (1讲)
结束语 | 栉风沐雨,砥砺前行!
Java性能调优实战
登录|注册

13 | 多线程之锁优化(中):深入了解Lock同步锁的优化方法

刘超 2019-06-18
你好,我是刘超。
今天这讲我们继续来聊聊锁优化。上一讲我重点介绍了在 JVM 层实现的 Synchronized 同步锁的优化方法,除此之外,在 JDK1.5 之后,Java 还提供了 Lock 同步锁。那么它有什么优势呢?
相对于需要 JVM 隐式获取和释放锁的 Synchronized 同步锁,Lock 同步锁(以下简称 Lock 锁)需要的是显示获取和释放锁,这就为获取和释放锁提供了更多的灵活性。Lock 锁的基本操作是通过乐观锁来实现的,但由于 Lock 锁也会在阻塞时被挂起,因此它依然属于悲观锁。我们可以通过一张图来简单对比下两个同步锁,了解下各自的特点:
从性能方面上来说,在并发量不高、竞争不激烈的情况下,Synchronized 同步锁由于具有分级锁的优势,性能上与 Lock 锁差不多;但在高负载、高并发的情况下,Synchronized 同步锁由于竞争激烈会升级到重量级锁,性能则没有 Lock 锁稳定。
我们可以通过一组简单的性能测试,直观地对比下两种锁的性能,结果见下方,代码可以在Github上下载查看。
通过以上数据,我们可以发现:Lock 锁的性能相对来说更加稳定。那它与上一讲的 Synchronized 同步锁相比,实现原理又是怎样的呢?
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Java性能调优实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(39)

  • Liam
    StampLock不支持重入,不支持条件变量,线程被中断时可能导致CPU暴涨

    作者回复: 回答很全面

    2019-06-18
    1
    16
  • -W.LI-
    老师好!读写锁那个流程图看不太明白,没有写线程的时候,判断不是当前线程在读就会进入CLF阻塞等待。
    问题1:不是可以并发读的嘛?按这图读线程也要阻塞等待的意思么?
    问题二:CLF阻塞队列里是读写线程公用的么?队列里,读写交替出现。那不就没法并发读了么?

    作者回复: 第一个问题,这里有一个公平锁和非公平锁的情况,如果是公平锁,即使无锁竞争的情况下,也会进入阻塞队列中排队获取锁;否则,会立即CAS获取到读锁。

    第二个问题,是公用的,这里同样涉及到了公平锁和非公平锁,读写线程对于程序来说都是一样的。如果是非公平锁,如果没有锁竞争的情况下CAS获取锁成功,是无需进入阻塞队列。如果是公平锁,都会进入阻塞队列。

    2019-06-18
    8
  • KingSwim
    重复是学习最好的方式——没有之一。虽然好几个Java专栏都会讲到锁的问题。但是,每次看完都是只能懂一部分。但是,每看完一个专栏就清晰一点,只有不断的重复,才能掌握好一个知识点。感觉复习同一个也会有效果(部分专栏看过 2 边,感觉有点耽误时间,专栏太多)。但是还是不如看新的专栏,因为同时还有其他知识点的收获。现在对温故而知新的”故“有了新的理解。另外,老师的 lock 是我看过专栏里面讲得最清晰的。
    2019-07-04
    7
  • 英长
    希望老师能多结合实践讲讲应用场景
    2019-06-19
    4
  • 密码123456
    为什么?因为锁不可重入?

    作者回复: 是的,StampedLock不支持可重入。如果在一些需要重入的代码中使用StampedLock,会导致死锁、饿死等情况出现。

    2019-06-18
    3
  • 趙衍
    谢谢老师的回复!关于StampedLock,我的理解是乐观读的时候,线程把stamp的值读出来,通过与运算来判断当前是否存在写操作。这个过程是不涉及CAS操作的。可是如果有线程需要修改当前的资源,要加写锁,那么就需要使用CAS操作修改stamp的值。不知道这样理解是否准确。
    此外,前排@-W.LI-同学提出的那个问题,并发读的时候也需要按照是否是公平锁进入CLH队列进行阻塞我还不是很明白,既然大家都是读操作,互相之间没有冲突,我每个线程都直接用CAS操作获取锁不就行了吗,为什么还要进队列阻塞等待呢?
    2019-06-19
    2
  • QQ怪
    老师这篇干货很多,看了2~3遍,大体理解了底层AQS锁原理,期待老师多多分享更多相关的文章
    2019-06-18
    2
  • -W.LI-
    StampedLock在写多读少的时候性能会很差吧

    作者回复: 是的,写多读少的性能没有优势。

    2019-06-18
    2
  • 我知道了嗯
    可重入锁是什么?另外什么场景下会使用到?

    作者回复: 可重入锁是指在同一个线程在前面方法中已获取锁了,再进入该线程的其他方法获取锁,此时不会因为之前获取锁而阻塞。
    平时我们很少遇到这种情况,例如在A方法中使用了对象锁,B方法中也使用了该对象锁,平时一般都是分别调用A方法和B方法,而后面由于业务需求刚好需要在A方法中调用B方法,此时就会需要锁支持可重入性。

    2019-06-20
    1
  • 趙衍
    老师我有几个问题:
    1.在ReentrantLock中,state这个变量,为0的时候表示当前的锁是没有被占用的。这个时候线程应该用CAS尝试修改state变量的值对锁进行抢占才对呀,为什么在您的图里当state=0的时候还需要判断是否为当前线程呢?
    2.老师提到读写锁在读多写少的情况下会使得写线程遭遇饥饿问题,那我是不是只需要将锁设置为公平锁,这样先申请写锁的线程就可以先获得锁,从而避免饥饿问题呢?
    3.StampedLock中引入了一个stamp版本对版本进行控制,那么对这个stamp变量进行写入的时候是否需要使用CAS操作?如果不是,那如何保证对stamp变量的读写是线程安全的呢?
    谢谢老师!

    作者回复: 第一个问题,是老师笔误,搞错方向了,现在已更正。

    第二个问题,如果读多写少的情况下,即使是公平锁,也是需要长时间等待,不是想获取时就能立即获取到锁。StampedLock如果是处于乐观读时,写锁是可以随时获取到锁。

    第三个问题,StampedLock源码中存在大量compareAndSwapObject操作来保证原子性。

    2019-06-18
    1
  • QQ怪
    刚想反馈图片一个字母写反了,刷新一下,立马被修复了,厉害厉害,佩服老师的效率
    2019-06-18
    1
  • 张学磊
    老师,tryOptimisticRead操作获取的不应该叫乐观读锁,应该是乐观读,是无锁的;StampedLock名字中没有Reentrant,所以不支持重入;StampedLock也不支持条件变量。

    作者回复: 这就是一种按版本号实现的读乐观锁,我们经常会在数据库更新操作时用到这种基于版本号实现的写乐观锁。

    对的,StampedLock不支持重入。

    2019-06-18
    1
  • Geek_f6fba7
    老师,lock锁中的线程阻塞进行的上下文切换会设计系统内核态和用户态的转换吗?啥时候会引起系统内核态和用户态转换成啊?.io流编程中会出现吗

    作者回复: lock锁阻塞不会带来进程间的上下文切换,IO流存在的,在09讲中讲到了

    2019-11-28
  • 涛哥迷妹
    RRW 加写锁 和 读锁 都需要判断低16位? 这块写锁是不是应该判读的是高16位有没有读锁,从而判断有没有冲突?

    作者回复: 从源码分析,都会进行高低位的判断,获取写锁时,如果state!=0 and w==0,就可以判断了此锁r!=0,也就是判断了高16位有没有读锁了。

    2019-11-10
  • 涛哥迷妹
    请教下,非公平锁是怎么玩的随机唤醒一个等待线程Node节点的,是压根不考虑CLH队列的顺序吗? 还是非公平锁压根不把获取锁失败的线程封装成Node加入到CLH队列中?
    2019-11-10
    1
  • 赤城
    老师,公平锁因为要维持一个线程执行的顺序,是不是性能相对非公平锁弱一些?

    作者回复: 一般占有锁时间非常短,队列的长度也不会太长,这个性能几乎可以忽略

    2019-11-08
  • godtrue
    课后思考及问题
    1:公平锁和非公平锁具体指什么?怎么体现?

    2:锁的状态可中断和不可中断具体是指什么意思?

    晚上加班状态可能不太好,感觉老师主要讲解了几种同步锁的实现原理,以及特点,如果能列个二维表就更好啦!

    作者回复: 我们进入到底层代码,可以发现其实公平锁和非公平锁的区别就是是否进入队列,公平锁是会进入到队列中排队等待唤醒,而非公平锁则是直接CAS获取锁。

    Lock锁如果监测到中断就直接throw new InterruptedException();抛出来了,所以可以响应中断。

    具体可参考源码。


    2019-09-09
  • 风轻扬
    老师,隐式锁只有synchronized这一种吗?

    作者回复: 对的

    2019-08-24
  • 一直不明白老师说的CAS是啥东东。具体描述下

    编辑回复: 你可以自己搜索了解下,极客时间其他专栏中也有介绍,App中搜索可以找到相关资料。

    2019-07-17
  • 嘉嘉☕
    好的,谢谢老师,就是看到图和文字是不一样的,确认一下
    2019-07-09
收起评论
39
返回
顶部