首先锁升级的过程:无锁->偏向锁->轻量级锁->重量级锁
使用实际案例举例子,来帮助大家理解:
我们要共享obj对象,加入现在只有一个线程A,线程id为10,此时它在执行前观察一下obj对象头中占用它的线程id是不是没有(也就是没人占用这个锁),如果是,则使用CAS将它改为10,当A执行完后看看现在obj中是不是10,如果是则表示没人跟我抢锁,我刚刚的执行有效,这就是偏向锁。
此时又来了一个线程B,线程id为20,还是上方一样A在执行使用CAS将obj对象头中线程id改为10,A继续执行了,B此时来了,它观察obj是偏向锁的状态,且对象头中有线程id且不为20,此时锁需要膨胀为轻量级锁,同时获取偏向锁的线程被挂起。
在轻量级锁的状态时,每个线程都会在栈帧中开辟一块锁记录空间(Lock Record),每次执行前先将对象头中mark word中信息copy进来,然后使用CAS尝试将mark word指针指向本线程的Lock record,如果成功则成功,否则说明期间被其他线程修改,他需要自旋转,也就是再执行,若自旋到达一定次数的时候,膨胀为重量级锁。
无锁:在未执行代码的时候,不会对对象加锁
经过上方形象的例子可以看出来,只要没膨胀为重量级锁,我们都没有进入到内核态,性能还是很高的哈 ,但是如果长时间的自旋,cpu占用可能也会很大。
推荐一个博主讲的,觉得写得很好,如果只是精简理解下过程,看我最上方的例子想必也都能明白了: https://blog.csdn.net/Javazhoumou/article/details/98866734