当线程访问代码块并获取锁对象时,首先会在java对象头和栈帧中记录偏向锁的threadId,又因为偏向锁不会主动释放锁,所以线程再次获取锁的时候,需要比较当前线程的threadId和java对象头中的threadId是否一致,如果一致则无需使用CAS来加锁和解锁;如果不一致,则需要确认java对象头中记录的线程是否存活。若没有存活,就将锁对象重置为无锁状态,其他线程可以竞争将其设置为偏向锁;若存活,就查找该线程的栈帧信息,如果线程还需要持有这个锁对象,将会暂停当前线程,撤销偏向锁,升级为轻量级锁;如果线程不再使用该锁对象,将会把锁对象设为无锁状态,重新偏向新的线程。
当一个线程已获取到轻量级锁的对象,另一线程也需要获取该锁对象时,会尝试自旋等待锁对象的释放。如果自旋达到一定次数,或者线程1拥有锁对象,线程2在自旋等待时,有线程3加入竞争锁对象,那么轻量级锁会升级为重量级锁。重量级锁会把除了拥有锁的线程都阻塞,防止cpu空转。