【Java面试】为什么引入偏向锁、轻量级锁,介绍下升级流程

语言: CN / TW / HK

Hi,我是Mic

一个工作了7年的粉丝来找我,他说最近被各种锁搞晕了。

比如,共享锁、排它锁、偏向锁、轻量级锁、自旋锁、重量级锁、

间隙锁、临键锁、意向锁、读写锁、乐观锁、悲观锁、表锁、行锁。

然后前两天去面试,被问到偏向锁、轻量级锁,结果没回答上来。

ok,关于Synchronized锁升级的原理,看看普通人和高手的回答。

普通人:

我觉得引入这些锁的目的应该是考虑到那个性能问题吧。

因为我记得好像是说Synchronized里面去加重量级锁的话,它的这个线程会存在这个阻塞就是会影响性能。所以才引入了偏向锁的一个机制。

然后升级的话就是说我们那些获取锁的时候就是按照偏向锁、轻量级锁和重量级锁的方式去竞争锁吧。

高手:

好的,面试官。

  1. Synchronized在jdk1.6版本之前,是通过重量级锁的方式来实现线程之间锁的竞争。

    之所以称它为重量级锁,是因为它的底层底层依赖操作系统的Mutex Lock来实现互斥功能。

    Mutex是系统方法,由于权限隔离的关系,应用程序调用系统方法时需要切换到内核态来执行。

    这里涉及到用户态向内核态的切换,这个切换会带来性能的损耗。

  2. 在jdk1.6版本中,synchronized增加了锁升级的机制,来平衡数据安全性和性能。简单来说,就是线程去访问synchronized同步代码块的时候,synchronized根据

    线程竞争情况,会先尝试在不加重量级锁的情况下去保证线程安全性。所以引入了偏向锁和轻量级锁的机制。

    偏向锁,就是直接把当前锁偏向于某个线程,简单来说就是通过CAS修改偏向锁标记,这种锁适合同一个线程多次去申请同一个锁资源并且没有其他线程竞争的场景。

    轻量级锁也可以称为自旋锁,基于自适应自旋的机制,通过多次自旋重试去竞争锁。自旋锁优点在于它避免避免了用户态到内核态的切换带来的性能开销。

  3. Synchronized引入了锁升级的机制之后,如果有线程去竞争锁:

​ 首先,synchronized会尝试使用偏向锁的方式去竞争锁资源,如果能够竞争到偏向锁,表示加锁成功直接返回。如果竞争锁失败,说明当前锁已经偏向了其他线程。

​ 需要将锁升级到轻量级锁,在轻量级锁状态下,竞争锁的线程根据自适应自旋次数去尝试抢占锁资源,如果在轻量级锁状态下还是没有竞争到锁,

​ 就只能升级到重量级锁,在重量级锁状态下,没有竞争到锁的线程就会被阻塞,线程状态是Blocked。

​ 处于锁等待状态的线程需要等待获得锁的线程来触发唤醒。

总的来说, Synchronized的锁升级的设计思想,在我看来本质上是一种性能和安全性的平衡,也就是如何在不加锁的情况下能够保证线程安全性。

这种思想在编程领域比较常见,比如Mysql里面的MVCC使用版本链的方式来解决多个并行事务的竞争问题。

以上就是我对这个问题的理解。

总结

锁在程序中是非常常见的内容,我们几乎每天与锁打交道,比如Mysql里面的行锁、表锁。

因此它的重要性也不言而喻。

我们从高手的回答中可以明显的看到高手对Synchronized的理解层次是非常高的。

喜欢我的作品的小伙伴记得点赞和收藏加关注。

版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Mic带你学架构

如果本篇文章对您有帮助,还请帮忙点个关注和赞,您的坚持是我不断创作的动力。欢迎关注「跟着Mic学架构」公众号公众号获取更多技术干货!