世界上不止有黑白两色,黑与白之间还是灰色的地带。

在成人的世界里,大多数人喜欢非黑即白的观点来看待一个问题,例如《十二公民》中那个刚开始所有人都认定的“一定是富二代杀S了自己的亲身父亲”,到最后大家理性分析和推测之后发现,事情根本不是大多数人(99.9%)以为的那样。

我们很容易被他人的说辞所误导,相信我们愿意相信的事,听我们愿意听的事,然后被舆论所支配,在人云亦云之中渐渐的迷失自我,然后丧失自己独立思考的能力。

学技术也是一样,尽信书不如无书,思考才是学习的目的,如果读书不是为了启迪自己的智慧,只是为了吹NB,那这个人有很大的概率会一事无成。

那此时我们再回过头来思考这个问题:轻量级锁一定比重量级锁快吗


正文

在回答这个问题之前,我们先来了解一下:什么是轻量级锁?什么是重量级锁?

锁概念

轻量级锁是 JDK 1.6 新增的概念,是相对于传统的重量级锁而已的一种状态,在 JDK 1.5 时,synchronized 是需要通过操作系统自身的互斥量(mutex lock)来实现,然而这种实现方式需要通过用户态与和核心态的切换来实现,但这个切换的过程会带来很大的性能开销,所以在 JDK 1.6 就引入了轻量级锁来避免此问题的发生。

轻量级锁执行过程

再讲轻量级锁执行过程之前,要先从虚拟机的对象头开始说起,HotSpot 的对象头(Object Header)分为两部分

  1. Mark Word 区域,用于存储对象自身的运行时数据,如哈希码(HashCode)、GC 分带年龄等;

  2. 用于存储指向方法区对象类型数据的指针(如果是数组对象的话,还有一个存储数组长度的额外信息)。

Mark Word 在 32 位系统中,有 32bit 空间,其中:

  • 25bit 用来存储 HashCode;

  • 4bit 用来存储对象的分带年龄;

  • 2bit 用来存储锁标志位,01=可偏向锁、00=轻量级锁、10=重量级锁;

  • 1bit 固定为 0。

再说会轻量级锁的执行过程,在代码进入同步块的时候,如果此对象没有被线程所占用,虚拟机会先将此线程的栈帧拷贝一份存储在当前对象的 Lock Record (锁记录) 区域中。

然后虚拟机再使用 CAS (Compare and Swap, 比较并交换) 将本线程的 Mark Word 更新为指向对象 Lock Record 区域的指针

如果更新成功,则表示这个线程拥有了该对象,轻量级锁添加成功,如果更新失败,虚拟机会先检查对象 Mark Word 是否指向了当前线程的线帧

如果是则表明此线程已经拥有了此锁,如果不是,则表明该锁已经被其他线程占用了。

如果有两条以上的线程在争抢死锁,那么锁就会膨胀为重量锁,Mark Word 中存储的就是指向重量级锁的互斥量指针,后面等待锁的线程也会进入阻塞状态。

从以上的过程,我们可以看出轻量级锁可以理解为是通过 CAS 实现的,理想的情况下是整个同步周期内不存在锁竞争,那么轻量锁可以有效的提高程序的同步性能

然而,如果情况相反,轻量级锁不但要承担 CAS 的开销还要承担互斥量的开销,这种情况下轻量级锁就会比重量级锁更慢,这就是我们本文的答案。


总结

轻量级锁不是在任何情况下都比重量级锁快的,要看同步块执行期间有没有多个线程抢占资源的情况

如果有,那么轻量级线程要承担 CAS + 互斥量锁的性能消耗,就会比重量锁执行的更慢

关于好与坏和对于错也是这个道理,有些事今天可能是对的,但明天有可能成错的了。

比如 JDK 1.5 时,你可以说同步线程只有一个方式:synchronized,然而 JDK 1.6 时又添加了 Lock。你昨天说的对的话,在明天可能就变成错的了。

所以对和错其实并不是那么绝对,它也没那么重要,重要的是你得有独立思考的能力和辨识对错认知。

有道无术,术可成;有术无道,止于术

欢迎大家关注Java之道公众号

有人说:轻量级锁一定比重量级锁快!我忍不住笑了

好文章,我在看❤️

相关文章:

  • 2021-11-27
  • 2021-12-13
  • 2021-07-31
  • 2021-06-16
  • 2022-12-23
  • 2022-12-23
  • 2021-05-24
猜你喜欢
  • 2021-11-30
  • 2021-10-11
  • 2022-12-23
  • 2022-01-14
  • 2022-12-23
  • 2021-07-14
相关资源
相似解决方案