这几天在逛B站时看别人的面试过程,问到了syntronized的锁膨胀过程,突然发现自己对这块不是很了解,在网上收集了一些资料记录一下:
首先:为什么要有锁膨胀过程:
在java 1.6之前,syntronized的操作是一项非常重的操作,属于重量级锁,但是Java的开发者们发现其实很多时候锁的竞争机制不是那么激烈的,没有必要在一个同步块中采取这样消耗性能的方式来处理,因为资源的竞争,加锁解锁,涉及到了用户态和内核态的转换。
所以在Java1.6的时候,他们对这个关键字进行了一些优化,这就是syntronized的锁膨胀过程。
那么,什么是syntronized的锁膨胀过程?
suotronized的锁膨胀过程为:无锁-》偏向锁-》轻量级锁-》重量级锁,膨胀的过程也正是syntronized的优化点,它可以根据资源竞争的程度来进行膨胀,锁膨胀过程不可逆,但是偏向锁可以被重置为无锁状态。
说到锁膨胀过程,就不得不提一下markword,他是在对象头中的一块内存区域,专门用于记录当前对象的锁状态的。
很多时候,我们说各种锁,其实他们的本质还是一块内存区域,简单理解:将markword中的标记位+1,就代表这个对象上锁,-1,代表释放锁,如果当前状态为0,说明没有上锁。
回到我们刚刚说的锁膨胀过程:
无锁过程:没有线程执行同步方法,代码块时候的状态
偏向锁:锁资源可以由同一个线程多次获得,降低了获取锁时候的性能开销,针对不存在锁竞争时候的情况
轻量级锁:通过cas操作markword中的标志位来实现,其中cas自选分为固定次数自旋和自适应自旋,达到自选阈值之后就转为重量级锁。它可以应用于竞争锁对象线程不多且持有锁时间不长的场景。
重量级锁:通过内部监视器monitor实现,monitor的本质是基于操作系统互斥mutex机制来实现的。
可以看到,它可以自适应地根据当前的锁竞争情况来自动调节锁的类型和程度,这样就减少了性能上的开销。
另外还有一点值得注意的是,在锁膨胀过程,其实是一个不可逆的过程,但是比较特殊的是,无锁状态和偏向锁状态是可以切换的。