面试官:小伙子知道synchronized的优化过程吗?我:嘚吧嘚吧嘚,面试官:出去!
写在开头
面试官:小伙子,多线程中锁用过吗?
我:那是自然!
面试官:那你知道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的优化过程吗?我:嘚吧嘚吧嘚,面试官:出去!的更多相关文章
- 【填坑往事】Android手机锁屏人脸解锁优化过程实录
背景 写这篇文章,主要是为了以后面试方便.因为我简历上写了,上一份工作的最大亮点是将人脸解锁的速度由1200ms优化到了600ms,所以这些内容已经回答无数遍了.但每次总觉得回答的不完整,或者说总感觉 ...
- 老掉牙的 synchronized 锁优化,一次给你讲清楚!
我们都知道 synchronized 关键字能实现线程安全,但是你知道这背后的原理是什么吗?今天我们就来讲一讲 synchronized 实现线程同步背后的原因,以及相关的锁优化策略吧. synchr ...
- 记一次Sql优化过程
这几天在写一个存储过程,反复优化了几次,从最开始的7分钟左右,优化到最后的几秒,并且这个过程中我的导师帮我指点了很多问题,这些指点都是非常宝贵的,独乐乐不如众乐乐,一起来分享这次的优化过程吧. 这个存 ...
- Java并发编程:Synchronized底层优化(偏向锁、轻量级锁)
Java并发编程系列: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程 ...
- 并发-Synchronized底层优化(偏向锁、轻量级锁)
Synchronized底层优化(偏向锁.轻量级锁) 参考: http://www.cnblogs.com/paddix/p/5405678.html 一.重量级锁 上篇文章中向大家介绍了Synchr ...
- Java多线程系列 基础篇07 synchronized底层优化
转载 http://www.cnblogs.com/paddix/ 作者:liuxiaopeng http://www.infoq.com/cn/articles/java-se-16-synchro ...
- java多线程02-----------------synchronized底层实现及JVM对synchronized的优化
java多线程02-----------------synchronized底层实现及JVM对synchronized的优化 提到java多线程,我们首先想到的就是synchronized关键字,它在 ...
- 【转】Java并发编程:Synchronized底层优化(偏向锁、轻量级锁)
一.重量级锁 上篇文章中向大家介绍了Synchronized的用法及其实现的原理.现在我们应该知道,Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的.但是监视器锁本 ...
- Synchronized底层优化(轻量级锁、偏向锁)(二)
一.重量级锁 上篇文章中向大家介绍了Synchronized的用法及其实现的原理.现在我们应该知道,Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的.但是监视器锁本质 ...
- php面试专题---MySQL常用SQL语句优化
php面试专题---MySQL常用SQL语句优化 一.总结 一句话总结: 原理,万变不离其宗:其实SQL语句优化的过程中,无非就是对mysql的执行计划理解,以及B+树索引的理解,其实只要我们理解执行 ...
随机推荐
- Centos7安装MySQL5.7和Redis6.0流水账
安装mysql 使用rpm包安装 yum remove mariadb-libs.x86_64 yum install perl rpm -ivh mysql-community-common-5.7 ...
- 【framework】ATMS启动流程
1 前言 ATMS 即 ActivityTaskManagerService,用于管理 Activity 及其容器(任务.堆栈.显示等).ATMS 在 Android 10 中才出现,由原来的 A ...
- patch命令
patch命令 patch指令让用户利用设置修补文件的方式.修改.更新原始文件,倘若一次仅修改一个文件,可直接在指令列中下达指令依序执行,如果配合修补文件的方式则能一次修补大批文件,这也是Linux系 ...
- Java I/O 教程(二) 介绍OutputStream 和 InputStream
OutputStream vs InputStream 我们来看一下两者的工作图: OutputStream 输出流 Java应用程序使用输出流将数据写入到某个目的地,可以是一个文件,数组,外围设备或 ...
- 树莓派/Linux ubuntu 开机自动改网络mac地址(主要适用于拷贝内存卡的情况/不同树莓派mac地址不同)
树莓派/Linux ubuntu 开机自动改网络mac地址(主要适用于拷贝内存卡的情况/不同树莓派mac地址不同) yaml文件名根据自己原卡中名字更改 address=$(cat /sys/clas ...
- CentOS8安装Docker报错问题解决
问题描述 CentOS版本:8.5.2111. # cat /etc/redhat-release CentOS Linux release 8.5.2111 安装准备: # 安装所需软件包 sudo ...
- PRINCE2系列一基于项目情境自定义解决方案
PRINCE2(PRojects IN Controlled Environments,受控环境下的项目管理) 对项目进行了如下定义:项目是按照一个被批准的商业论证,为了交付一个或多个商业产品而创建的 ...
- C++ STL //vector容器存放内置数组
1 //STL初始 2 // 3 //vector容器存放内置数组 4 5 #include <iostream> 6 #include <string> 7 #include ...
- 在anaconda中为jupyter安装代码自动补全或代码自动提示功能,jupyter nbextensions不显示拓展,另附格式化代码插件的安装方法
操作步骤 进入命令行环境.我使用的是conda.有两种方式进入命令行. 方法1:通过anconda navigator界面,选择environments,选择对应环境名,选择open terminal ...
- forward配置
Adb connect 127.0.0.1:62001 adb forward tcp:27042 tcp:27042 #设置端口转发 adb forward tcp:27043 tcp:27 ...