写在开头

面试官:小伙子,多线程中锁用过吗?

我:那是自然!

面试官:那你知道synchronized的优化吗?

我:synchronized作为重锁,开销大,在早期不被推荐使用,后期进行了优化,至于怎么优化的话,您让我想想哈...

面试官:好的,那你出去好好想吧!

对于synchronized的优化,虽然被问到的场景不多,但在很多网友发的面经中发现很多人都会挂在这个点上。

在我们初学锁时,很多人可能都觉得它是一个重量级锁,代码中不建议使用,但其实现如今经过了层层优化后,synchronized被广泛的应用在了JVM源码以及众多开源框架中,我们今天就来一起学习一下synchronized的优化过程!

对象锁的四种状态

首先,我们这里要记住一个Java迭代版本JDK1.6,这个版本对于synchronized来说是划时代的,在此之前,synchronized确实是一种重量级悲观锁,这个时候的它使用起来极耗资源,为所有高效开发者所弊病,但在1.6版本之后,引入了“偏向锁”和“轻量级锁” 的概念,这极大减少了获取synchronized锁和释放锁所需资源,synchronized重获新生!

在此之后,对象的锁便拥有了4种状态,根据锁的级别从低到高可分为:

无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁

无锁

无锁其实很好理解,就是没有对共享资源进行任何锁定,所有线程都可以去访问并修改同一资源,但同时只能有一个线程修改成功,其他线程不断尝试直至成功,并会将原内容覆盖。

偏向锁

偏向锁,指的就是偏向第一个加锁线程,对象的代码一直被同一线程执行,不存在多个线程竞争,该线程在后续的执行中自动获取锁,降低获取锁带来的性能开销。

轻量级锁

轻量级锁是指当锁是偏向锁的时候,被第二个线程 B 所访问,此时偏向锁就会升级为轻量级锁,线程 B 会通过自旋的形式尝试获取锁,线程不会阻塞,从而提高性能。

重量级锁

指当有一个线程获取锁之后,其余所有等待获取该锁的线程都会处于阻塞状态。

重量级锁通过对象内部的监视器(monitor)实现,而其中 monitor 的本质是依赖于底层操作系统的 Mutex Lock 实现,操作系统实现线程之间的切换需要从用户态切换到内核态,切换成本非常高。所以在没有被优化之前,synchronized这种重量级锁,才不受重视!

对象锁的存储

学习完对象锁的四种状态后,我们继续思考下一个问题,既然对象锁有四种状态,那它们是存储在哪里的呢?

会联想的同学,我想已经猜出了大概,首先在Java中的锁都是基于对象的,既然基于对象,那它存在的地方大概率要在对象中,而我们知道在JVM中,对象分为三个部分对象头、实例数据、字节对齐,其中对象头又由Mark Word和Klass Point构成,而Mark Word(标记字段)用于存储对象自身的运行时数据,例如存储对象的HashCode,分代年龄、锁标志位等信息,是synchronized实现轻量级锁和偏向锁的关键。我们64位虚拟机为例看下图:

当对象状态是偏向锁时,MarkWord中存储了偏向线程的ID,并且将是否偏向标志置为1;当对象状态是轻量级锁时,Mark Word存储的是指向线程栈中Lock Record的指针;当状态为重量级锁时,Mark Word为指向monitor(监视器)对象的指针。

synchronized 锁升级的过程

有了上面的知识储备,我们趁着打铁,来聊一聊synchronized 锁升级的过程,由低到高,逐渐升级。

1️⃣首先,在锁对象的对象头里面有一个 threadid 字段,未访问时 threadid 为空,这时是无锁状态,任何线程都可竞争获取共享资源;

2️⃣ 先得到共享资源的线程,其线程ID会被记录到Mark Word中,此时锁状态为偏向锁;

3️⃣ 当后续还有线程去获取共享资源时,会先判断 threadid 是否与其线程 id 一致。如果一致则可以直接使用此对象;如果不一致,则升级偏向锁为轻量级锁,通过自旋循环一定次数来获取锁;

4️⃣自旋的线程在自旋过程中,成功获得资源(即之前获的资源的线程执行完成并释放了共享资源),则整个状态依然处于 轻量级锁的状态,如果自旋失败 。

5️⃣进入重量级锁的状态,这个时候,自旋的线程进行阻塞,等待之前线程执行完成并唤醒自己。

结尾彩蛋

如果本篇博客对您有一定的帮助,大家记得留言+点赞+收藏呀。原创不易,转载请联系Build哥!

如果您想与Build哥的关系更近一步,还可以关注“JavaBuild888”,在这里除了看到《Java成长计划》系列博文,还有提升工作效率的小笔记、读书心得、大厂面经、人生感悟等等,欢迎您的加入!

面试官:小伙子知道synchronized的优化过程吗?我:嘚吧嘚吧嘚,面试官:出去!的更多相关文章

  1. 【填坑往事】Android手机锁屏人脸解锁优化过程实录

    背景 写这篇文章,主要是为了以后面试方便.因为我简历上写了,上一份工作的最大亮点是将人脸解锁的速度由1200ms优化到了600ms,所以这些内容已经回答无数遍了.但每次总觉得回答的不完整,或者说总感觉 ...

  2. 老掉牙的 synchronized 锁优化,一次给你讲清楚!

    我们都知道 synchronized 关键字能实现线程安全,但是你知道这背后的原理是什么吗?今天我们就来讲一讲 synchronized 实现线程同步背后的原因,以及相关的锁优化策略吧. synchr ...

  3. 记一次Sql优化过程

    这几天在写一个存储过程,反复优化了几次,从最开始的7分钟左右,优化到最后的几秒,并且这个过程中我的导师帮我指点了很多问题,这些指点都是非常宝贵的,独乐乐不如众乐乐,一起来分享这次的优化过程吧. 这个存 ...

  4. Java并发编程:Synchronized底层优化(偏向锁、轻量级锁)

    Java并发编程系列: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程 ...

  5. 并发-Synchronized底层优化(偏向锁、轻量级锁)

    Synchronized底层优化(偏向锁.轻量级锁) 参考: http://www.cnblogs.com/paddix/p/5405678.html 一.重量级锁 上篇文章中向大家介绍了Synchr ...

  6. Java多线程系列 基础篇07 synchronized底层优化

    转载 http://www.cnblogs.com/paddix/ 作者:liuxiaopeng http://www.infoq.com/cn/articles/java-se-16-synchro ...

  7. java多线程02-----------------synchronized底层实现及JVM对synchronized的优化

    java多线程02-----------------synchronized底层实现及JVM对synchronized的优化 提到java多线程,我们首先想到的就是synchronized关键字,它在 ...

  8. 【转】Java并发编程:Synchronized底层优化(偏向锁、轻量级锁)

     一.重量级锁 上篇文章中向大家介绍了Synchronized的用法及其实现的原理.现在我们应该知道,Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的.但是监视器锁本 ...

  9. Synchronized底层优化(轻量级锁、偏向锁)(二)

    一.重量级锁 上篇文章中向大家介绍了Synchronized的用法及其实现的原理.现在我们应该知道,Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的.但是监视器锁本质 ...

  10. php面试专题---MySQL常用SQL语句优化

    php面试专题---MySQL常用SQL语句优化 一.总结 一句话总结: 原理,万变不离其宗:其实SQL语句优化的过程中,无非就是对mysql的执行计划理解,以及B+树索引的理解,其实只要我们理解执行 ...

随机推荐

  1. ES6学习 第四章 字符串的新增方法

    前言 本章介绍字符串对象的新增方法.不常用的方法不做重点笔记. 本章原文链接:字符串的新增方法 includes().startsWith().endsWith() 确定一个字符串是否包含在另一个字符 ...

  2. NC24870 [USACO 2009 Dec G]Video Game Troubles

    题目链接 题目 题目描述 Farmer John's cows love their video games! FJ noticed that after playing these games th ...

  3. NVME(学习笔记三)—PMR

    PMR(Persistent Memory Region)持久性内存区域 NVM Express在2019年完成了NVMe 1.4规范的制定,新的NVMe协议带来了大量的全新特性,尤其在纠错.强化性能 ...

  4. 【Unity3D】人物跟随鼠标位置

    1 游戏对象 ​ 2D动画和人体模型及动画中介绍了 Aniamtion.Animator.人体模型.人体骨骼.人体动画等基础知识,本文将通过 "人物跟随鼠标位置" 案例加强对 Un ...

  5. Linux后台进程启停脚本模板

    目录 启动脚本 停止脚本 在Linux上启动程序后台运行时,往往需要输入一堆复杂的命令,为了能快速编写一个完善的启动脚本,整理一个通用的启停脚本模板如下. 脚本支持从任意位置执行,不存在路径问题,启动 ...

  6. 海康摄像头开发笔记(一):连接防爆摄像头、配置摄像头网段、设置rtsp码流、播放rtsp流、获取rtsp流、调优rtsp流播放延迟以及录像存储

    前言   Hik防爆摄像头录像,因为防爆摄像头会有对应的APP软件,与普通的网络摄像头和球机不一样,默认认为它不可以通过web网页配置,所以弄了个来实测确认.  经测试实际上也是可以通过web网页配置 ...

  7. 擅长使用iter

    def populate_ranks(votes, ranks): names = list(votes.keys()) names.sort(key=votes.get, reverse=True) ...

  8. 【算法day5】排序算法的稳定性及其汇总

    稳定性 定义:值相同的元素在排序完成之后能否保证原有的次序不变(同样值的个体之间,如果不因为排序而改变相对次序,这个排序就是有稳定性的,否则就没有) 举例: [2,1,3,1]-->[1,1,2 ...

  9. React实现导航栏点击高亮

    在jquery中实现导航栏的切换只需要一行代码找到同级其他元素removeClass以及添加点击元素addClass就可以实现了,但是React没法直接找到同级元素,这个时候需要一点js中的思维,根据 ...

  10. 【Azure 应用服务】Azure Function 中运行Powershell 脚本,定位 -DefaultProfile 引发的错误

    问题描述 突然之间,使用PowerShell脚本 Get-AzVirtualNetwork 获取虚拟网络信息时,如果带上  -DefaultProfile $sub 参数,就出现 Azure cred ...