JAVA笔记JAVA笔记
首页
  • Java SE

    • 事务全知道
    • 全局异常处理
    • 数据类型转换
    • Synchronized底层实现
  • Java EE

    • 网络
  • Spring

    • Spring技术总结
  • Spring Boot

    • 异步编程
    • springboot基础配置
    • springboot瘦身部署
    • 如何保证缓存与数据库的双写一致性?
    • Spring Boot中使用redis缓存
    • springboot-mybaits-druid
  • 一次jvm问题
  • JVM基础
  • JVM问题排查
  • FGC问题排查
  • 数据库
  • 数据优化
  • aop读写分离实战
  • 分布式事务
  • 分布式限流
  • 分布式Id
  • 分布式Session
  • Dubbo
首页
  • Java SE

    • 事务全知道
    • 全局异常处理
    • 数据类型转换
    • Synchronized底层实现
  • Java EE

    • 网络
  • Spring

    • Spring技术总结
  • Spring Boot

    • 异步编程
    • springboot基础配置
    • springboot瘦身部署
    • 如何保证缓存与数据库的双写一致性?
    • Spring Boot中使用redis缓存
    • springboot-mybaits-druid
  • 一次jvm问题
  • JVM基础
  • JVM问题排查
  • FGC问题排查
  • 数据库
  • 数据优化
  • aop读写分离实战
  • 分布式事务
  • 分布式限流
  • 分布式Id
  • 分布式Session
  • Dubbo
  • Java EE

    • 网络
  • Java SE

    • Synchronized底层实现
    • 事务全知道
    • 全局异常处理
    • 数据类型转换

Synchronized底层实现

JAVA线程阻塞的代价

java 的线程是映射到原生操作系统线程上的,阻塞和唤醒操作系统都需要操作系统介入的,需要在用户态和核心态之间转换。这种切换会耗费大量操作系统资源,因为用户态和核心态都有各自专用的内存空间、寄存器等。用户态切换到内核态需要传递许多变量、参数给内核,内核也需要保存好用户态在切换时的寄存器值和变量。

markword对象头标识

markword是java对象数据结构中的一部分,他的最后2bit是锁状态标识,用来标记当前对象所处的状态。

  • 01:未锁定(对象的hash值、对象年龄分代)
  • 00:轻量级锁(指向锁记录的指针)
  • 10:重量级锁(指向重量级锁的指针)
  • 01:偏向锁(偏向线程ID、偏向时间、对象年龄代)

Synchronized 实现原理

锁升级

锁的状态:无锁状态、偏向锁、轻量级锁状态、重量级锁状态(级别由低到高)

偏向锁

偏向锁他会偏向第一次访问的线程,当线程获取锁对象时,会在java对象头markword中记录偏向锁的threadID,并不会主动释放偏向锁。当同一个线程再次获取锁时会比较当前的threadID与对象头中的threadID是否一致。如果一致则不需要通过CAS来加锁、解锁。如果不一致并且线程还需要持续持有锁,则暂停当前线程撤销偏向锁,升级为轻量级锁。如果不在需要持续持有锁则锁对象头设为无锁状态,重新设置偏向锁。

轻量级锁

轻量级锁由偏向锁升级而来,偏向锁运行在一个线程同步块时,第二个线程加入锁竞争的时候,偏向锁就会升级为轻量级锁。

轻量级锁过程:

  1. 线程由偏向锁升级为轻量级锁时,会先把锁的对象头MarkWord复制一份到线程的栈帧中,建立一个名为锁记录空间(Lock Record),用于存储当前Mark Word的拷贝。
  2. 虚拟机使用cas操作尝试将对象的Mark Word指向Lock Record的指针,并将Lock record里的owner指针指对象的Mark Word。
  3. 如果cas操作成功,则该线程拥有了对象的轻量级锁。第二个线程cas自选锁等待锁线程释放锁。
  4. 如果多个线程竞争锁,轻量级锁要膨胀为重量级锁,Mark Word中存储的就是指向重量级锁(互斥量)的指针。其他等待线程进入阻塞状态。

总结

synchronized的执行过程:

  1. 检测Mark Word里面是不是当前线程的ID,如果是,表示当前线程处于偏向锁
  2. 如果不是,则使用CAS将当前线程的ID替换Mard Word,如果成功则表示当前线程获得偏向锁,置偏向标志位1
  3. 如果失败,则说明发生竞争,撤销偏向锁,进而升级为轻量级锁。
  4. 在线程的栈帧生成一条锁记录,当前线程使用CAS将对象头的Mark Word替换为锁记录指针,如果成功,当前线程获得锁(也就是那个对象指向锁记录,哪个对象持有锁,没持有就CAS自旋,自旋失败就升级为重量级锁)
  5. 如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。
  6. 如果自旋成功则依然处于轻量级状态。
  7. 如果自旋失败,则升级为重量级锁。
最近更新:: 2025/4/3 14:27
Contributors: llengleng
Next
事务全知道