栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

synchronized -- 偏向锁

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

synchronized -- 偏向锁

轻量级锁在没有竞争时(就自己这个线程),每次重入仍然需要执行CAS操作。

Java6 中引入了偏向锁来做进一步优化:只有第一次使用CAS将线程ID设置到对象的Mark Word头,之后发现这个线程ID是自己的就表示没有竞争,不用重新CAS,以后只要不发生竞争,这个对象就归该线程所有。

我们看上述代码

每次进行CAS,且需要创建锁记录,均会影响CPU性能 

 对象头格式

一个对象创建时:

如果开启了偏向锁(默认开启),那么对象创建后,Mark Word 的后三位为101,这时他的thread,epoch,age都为0偏向锁时默认延迟的,不会在程序启动时立即生效,如果想避免延迟,可以加VM参数 - XX : BiasedLockingStartupDelay来禁用延迟如果没有开启偏向锁,那么对象创建后,markword值为0x01

程序刚刚启动就立即创建对象,发现后三位是001,即无锁状态。(JOL工具查看对象的对象头)

对程序改写,加一个sleep

 可以发现几秒后,创建的对象,就会变成有锁的了,加锁就仅仅将线程id存入对象头中

 处于偏向锁的对象解锁后,线程id仍存储于对象头中。

调用一个对象的hashCode()方法,会禁用这个对象的偏向锁

 为什么调用对象的哈希码就会禁用对象的偏向锁呢?

当对象处于偏向锁的状态的时候,存完线程id等之后,就没地方存储hashcode了

为什么轻量级锁和重量级锁和重量级锁就不需要在对象头中存储hashcode呢?

因为轻量级锁的hashcode存储在锁对象中,而重量级锁的hashcode存储在Monitor对象中

输出的结果如下,首先是未加锁状态,加锁之后,将t1线程的线程id放入对象头中,

解锁后,线程id依然会在对象头中,即第三行的输出和第二行的输出一致。

进入t2线程,打印d对象的对象头

然后t2线程尝试加锁,再次打印对象头,加的是状态为00的轻量级锁

最后t2线程释放锁,最终状态为001,不可偏向状态。

调用 wait/notify 也会撤销偏向锁状态,升级为重量级锁。

锁消除

Score是对两个代码的执行时间的评分,我们发现,评分基本相同,为什么第二段代码加了锁,执行所消耗的时间却和第一段代码基本一致呢

Java运行时有一个JIT即时编译器,会对Java代码的热点代码,进行优化,其中一个手段锁消除,检测到上面代码的Object锁对象,不会从这个方法中逃逸,即不会被共享,那么加锁就毫无意义了,synchronized的就直接被优化掉了,即b()方法根本就没有被加锁。 

当关闭锁消除的时候,发现时间明显上升了 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/759879.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号