在 JDK1.5 之前,面对 Java 并发问题, synchronized 是一招鲜的解决方案:
拿同步块来举例:
public void test(){
synchronized (object) {
i++;
}
}
经过 javap -v
编译后的指令如下:
成重量级锁,阻塞线程排队竞争,也就有了轻量级锁升级成重量级锁的过程
上面我们用到的 JOL 版本为 0.14
, 带领大家快速了解一下位具体值,接下来我们就要用 0.16
版本查看输出结果,因为这个版本给了我们更友好的说明,同样的代码,来看输出结果:
吗?
标记3
: 新线程进入同步代码块,升级成了轻量级锁标记4
: 新线程轻量级锁退出同步代码块,主线程查看,变为不可偏向状态标记5
: 由于对象不可偏向,同场景1主线程再次进入同步块,自然就会用轻量级锁至此,场景一二三可以总结为一张图:
结论就是:即便初始化为可偏向状态的对象,一旦调用
Object::hashCode()
或者System::identityHashCode(Object)
,进入同步块就会直接使用轻量级锁
假如已偏向某一个线程,然后生成 hashcode,然后同一个线程又进入同步块,会发生什么呢?来看代码:
来看运行结果:
结论就是,wait 方法是互斥量(重量级锁)独有的,一旦调用该方法,就会升级成重量级锁(这个是面试可以说出的亮点内容哦)
最后再继续丰富一下锁对象变化图:
一句话解释就是维护成本太高
最终就是,JDK 15 之前,偏向锁默认是 enabled,从 15 开始,默认就是 disabled,除非显示的通过 UseBiasedLocking 开启