1、偏向锁
2、轻量级锁
(1)轻量级锁加锁
线程在执行同步块之前,JVM会先在当前线程的栈桢中创建用于存储锁记录的空间,并将对象头中的Mark Word复制到锁记录中,官方称为Displaced Mark Word。然后线程尝试使用CAS将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失
败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。
(2)轻量级锁解锁
轻量级解锁时,会使用原子的CAS操作将Displaced Mark Word替换回到对象头,如果成功,则表示没有竞争发生。如果失败,表示当前锁存在竞争,锁就会膨胀成重量级锁
从图中可以看出,所标志位是00代表轻量级锁,轻量级锁又称自旋锁、无锁(存在歧义尽量不要用此称);标志位是10代表重量级锁;标志位是11代表GC回收;标志位是001代表无锁状态,101代表是偏向锁
锁升级的过程
偏向锁直接调用wait()方法-->重量级锁
匿名偏向--->偏向锁:在synchronized()-->synchronized(o)
偏向锁自旋锁都是用户空间完成;重量级锁是需要向内核申请
当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,从无锁状态升级为偏向锁---->出现竞争,另一个进程争抢资源,就会撤销原来的偏向锁,两个进程开始竞争把对象头中的Mark Word替换为各自的LR指针,一个成功则另一个自旋等待--->当有线程超过10次自旋,-XX:PreBlockSpin,或者自旋线程数超过CPU核数的一半时,锁就会膨胀成重量级锁。在1.6之后,加入自适应自旋Adapative Self Spinning , 由JVM自己控制何时膨胀为重量级锁
为什么有轻量级锁还要有重量级锁?
自旋是消耗CPU资源的,如果锁的时间长,或者自旋线程多,CPU会被大量消耗,重量级锁会把自旋的那些进程,放到WaitSet等待队列,不需要消耗CPU,等待调用
偏向锁是否一定比自旋锁效率高?不一定
不一定,在明确知道会有多线程竞争的情况下,偏向锁肯定会涉及锁撤销,这时候直接使用自旋锁效率更高。所以在JVM启动过程,会有很多线程竞争(明确),所以默认情况启动时不打开偏向锁,过一段儿时间再打开-XX:BiasedLockingstartupDelay=o (一段时间应该是4s)【偏向锁未启动】