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()方法根本就没有被加锁。 

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值