java synchronized中锁的升级过程

Posted QQ_851228082

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java synchronized中锁的升级过程相关的知识,希望对你有一定的参考价值。

synchronized 偏向锁、轻量级锁、重量级锁、自旋锁

对象头

java对象在jvm内存中分为对象头、对象体两部分,对象头中有些标记信息,称为标记字(mark word),mark word主要有对象hash值、gc年龄、锁标记、线程id

synchronized中锁的升级过程

对象刚创建时,没有锁,第一个线程来时,使用CAS(Compare And Swap)将当前线程id设置到对象头(Mark Word)中,第二次再获取锁时,不需要进行CAS,只比较一下对象头中的线程id是否与当前线程id相同,如果相同则获取锁,这就叫偏向锁;如果不相等,则检查持有锁线程的状态,如果持有锁线程已经消亡或者已经退出同步块,则撤销锁,重新偏向;如果原有线程还需要锁,则升级为轻量级锁,首先在持有锁的线程栈中创建锁记录,将对象头中的mark word复制到锁记录,对象头有指针指向锁记录,当前线程进入自旋,如果自旋超过一定次数或者有第三个线程参与锁竞争,则认为锁竞争激烈,锁膨胀为重量级锁;

  • 偏向锁
    • 是假设没有线程竞争,偏向第一个获取锁的线程,对象会偏向上次获取到锁的线程。
  • 自旋
    • 通常物理处理器都是多核,当线程1持有锁时,线程2尝试获取锁,通常我们认为线程同步块应该会很快结束,为了避免线程切换引起的性能开销,让线程2自旋(占用另外一个cpu空转,可以认为是while循环),这就是自旋;轻量级锁搭配自旋锁使用。
  • 轻量级锁
    • 锁竞争不激烈,持有锁线程正常执行,当前线程自旋;
  • 重量级锁
    • 适应锁竞争激烈情景,持有锁的线程正常执行,当前线程会阻塞挂起。

显而易见,偏向锁、轻量级锁是乐观锁;重量级锁是悲观锁;

引用知乎的一张图,图里锁升级的过程很清晰。

问题

轻量级锁轻量在哪里?重量级锁重量在哪里?
这个问题曾困扰了我很长时间,《深入理解 Java 虚拟机–JVM高级特性与最佳实践》说重量级锁通过互斥量实现,但我对互斥量不懂,其实互斥量只是手段,最终引起线程的切换,重就重在线程切换
轻量级锁的轻量是相当于重量级锁而言的,那什么是重量级锁,重量级锁使用操作系统互斥量实现的,如果线程1持有重量级锁,线程2也想获得这把锁时,因为已经被持有,线程2会被挂起阻塞,这个线程1释放锁后,线程2再被唤醒,这个过程就涉及到线程的阻塞、唤醒,阻塞唤醒牵扯到内核态、用户态的切换,线程切换的成本是很大的,所以叫重量级锁;而轻量级锁不牵扯到线程切换,当线程2获取锁时,看到线程1已经持有锁,那么线程2会自旋(使用另外一个物理cpu执行while死循环),这个过程没有线程切换,所以是轻量级。

以上是关于java synchronized中锁的升级过程的主要内容,如果未能解决你的问题,请参考以下文章

Java中锁升级的探究

30分钟彻底弄懂 synchronized 锁升级过程

30分钟彻底弄懂 synchronized 锁升级过程

java中锁的应用

java中锁的应用

Java synchronized锁的底层实现概述