java锁升级过程

java锁升级过程java中对象锁有4种状态:(级别从低到高)1.无锁状态2.偏向锁状态3.轻量级锁状态4.重量级锁状态对象头分两部分信息,第一部分用于存储哈希码、GC分代年龄等,这部分数据被称为”MarkWord”。在32位的HotSpot虚拟机中对象未被锁定的状态下,MarkWord的32bit空间中的25bit用于存储对象哈希码,4bit用于存储对象分代年龄,2bit用于存储锁标志位,1bit固…

大家好,又见面了,我是你们的朋友全栈君。

java中对象锁有4种状态:(级别从低到高)
1.无锁状态
2.偏向锁状态
3.轻量级锁状态
4.重量级锁状态

对象头分两部分信息,第一部分用于存储哈希码、GC分代年龄等,这部分数据被称为”Mark Word”。在32位的HotSpot虚拟机中对象未被锁定的状态下,Mark Word的32bit空间中的25bit用于存储对象哈希码,4bit用于存储对象分代年龄,2bit用于存储锁标志位,1bit固定为0,在其他状态(轻量级锁定、重量级锁定、GC标记、可偏向)下对象的存储内容见下表:
在这里插入图片描述
锁升级的方向是:无锁——>偏向锁——>轻量级锁——>重量级锁,并且膨胀方向不可逆。

1.偏向锁
偏向锁是JDK6中引入的一项锁优化,大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁。
偏向锁会偏向于第一个获得它的线程,如果在接下来的执行过程中,该锁没有被其他的线程获取,则持有偏向锁的线程将永远不需要同步。

2.轻量级锁
如果明显存在其它线程申请锁,那么偏向锁将很快升级为轻量级锁。

3.自旋锁
自旋锁原理非常简单,如果持有锁的线程能在很短时间内释放锁资源,那么那些等待竞争锁的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态,它们只需要等一等(自旋),等持有锁的线程释放锁后即可立即获取锁,这样就避免用户线程和内核的切换的消耗。

4.重量级锁
指的是原始的Synchronized的实现,重量级锁的特点:其他线程试图获取锁时,都会被阻塞,只有持有锁的线程释放锁之后才会唤醒这些线程。

锁升级场景:

场景1: 程序不会有锁的竞争。
那么这种情况我们不需要加锁,所以这种情况下对象锁状态为无锁。

场景2: 经常只有某一个线程来加锁。
加锁过程:也许获取锁的经常为同一个线程,这种情况下为了避免加锁造成的性能开销,所以并不会加实际意义上的锁,偏向锁的执行流程如下:
1、线程首先检查该对象头的线程ID是否为当前线程;
2、A:如果对象头的线程ID和当前线程ID一直,则直接执行代码;B:如果不是当前线程ID则使用CAS方式替换对象头中的线程ID,如果使用CAS替换不成功则说明有线程正在执行,存在锁的竞争,这时需要撤销偏向锁,升级为轻量级锁。
3、如果CAS替换成功,则把对象头的线程ID改为自己的线程ID,然后执行代码。
4、执行代码完成之后释放锁,把对象头的线程ID修改为空。

场景3: 有线程来参与锁的竞争,但是获取锁的冲突时间很短。
当开始有锁的冲突了,那么偏向锁就会升级到轻量级锁;线程获取锁出现冲突时,线程必须做出决定是继续在这里等,还是回家等别人打电话通知,而轻量级锁的路基就是采用继续在这里等的方式,当发现有锁冲突,线程首先会使用自旋的方式循环在这里获取锁,因为使用自旋的方式非常消耗CPU,当一定时间内通过自旋的方式无法获取到锁的话,那么锁就开始升级为重量级锁了。

场景4: 有大量的线程参与锁的竞争,冲突性很高。
我们知道当获取锁冲突多,时间越长的时候,我们的线程肯定无法继续在这里死等了,所以只好先休息,然后等前面获取锁的线程释放了锁之后再开启下一轮的锁竞争,而这种形式就是我们的重量级锁。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/161185.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • uniqueidentifier转换_unique函数哪个版本有

    uniqueidentifier转换_unique函数哪个版本有uniqueidentifier中文含义“唯一的标识符”。uniqueidentifier数据类型是16个字节的二进制值,应具有唯一性,必须与NEWID()函数配合使用。uniqueidentifier数据类型与identity自增不同,不会为插入的新行自动生成新的ID,新值由NEWID()函数指定。NEWID()函数值会生成全球唯一的标识,标识由网卡号和CPU时钟组成,如:6

    2022年9月7日
    6
  • mysqlnd cannot connect to MySQL 4.1+ using the …

    mysqlnd cannot connect to MySQL 4.1+ using the …

    2021年8月20日
    51
  • postgreSql修改端口后psql命令行链接报错”/tmp/.s.PGSQL.5432“

    postgreSql修改端口后psql命令行链接报错”/tmp/.s.PGSQL.5432“今天修改pg的端口号port改成54328后重启完数据库的时候直接psql进库的时候进不去[postgres@iZ8vbifqgkwljcq9ccpkg7Zdata]$psqlpsql:couldnotconnecttoserver:NosuchfileordirectoryIstheserverrunninglocallyandacceptingconnectionsonUnixdomainsocket”/tmp/.s.PGSQL.5432这时,

    2022年6月19日
    58
  • pycharm安装后如何使用_Pycharm安装教程

    pycharm安装后如何使用_Pycharm安装教程http://blog.csdn.net/u014044812/article/details/78727496 激活码https://www.cnblogs.com/beginner-boy/p/7785041.html由于本人也是开发语言的学习小白,所以对于开发时使用的工具也不算太熟悉,不过这里还是要推荐一下本人使用过的两款工具:1、pycharm ;2、eclipse这是我用的比较顺…

    2022年8月28日
    3
  • 借助栈来实现单链表的逆置运算_中缀后缀表达式互相转换

    借助栈来实现单链表的逆置运算_中缀后缀表达式互相转换原题链接算术表达式有前缀表示法、中缀表示法和后缀表示法等形式。日常使用的算术表达式是采用中缀表示法,即二元运算符位于两个运算数中间。请设计程序将中缀表达式转换为后缀表达式。输入格式:输入在一行中给出不含空格的中缀表达式,可包含+、-、*、\以及左右括号(),表达式不超过20个字符。输出格式:在一行中输出转换后的后缀表达式,要求不同对象(运算数、运算符号)之间以空格分隔,但结尾不得有多余空格。输入样例:2+3*(7-4)+8/4输出样例:2 3 7 4 – * + 8 4 / +注意

    2022年8月8日
    2
  • 色环电阻的阻值识别

    色环电阻的阻值识别

    2021年6月12日
    132

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号