Java中synchronized的底层原理

https://blog.csdn.net/RollingCode_999/article/details/145591346

上一篇讲了为什么需要同步,以及 synchronized 关键字的使用,这一篇分析一下 synchronized的底层原理

对象头中的Mark Word

每个对象头中都包含了对象头信息,与锁相关的关键部分是Mark Word(标记字段)

Mark Word 会根据锁状态动态变化,存储锁标志位,线程ID等信息

以下为 Mark Word 的四种锁状态信息:

  1. Normal(无锁)
  2. Biased(偏向锁)
  3. Lightweight Locked(轻量级锁)
  4. ptr_to_heavyweight_monitor:62 (重量级锁)
|---------------------------------------------------|--------------------|
|                  Mark Word (64 bits)              |       State        |
|---------------------------------------------------|--------------------|
| unused:25 | identity_hashcode:31 | unused:1 | age:4 | biased_lock:0 | 01 |   Normal(无锁)
|---------------------------------------------------|--------------------|
| thread:54 |         epoch:2      | unused:1 | age:4 | biased_lock:1 | 01 |   Biased(偏向锁)
|---------------------------------------------------|--------------------|
|               ptr_to_lock_record:62          |               00       |   Lightweight Locked(轻量级锁)
|---------------------------------------------------|--------------------|
|               ptr_to_heavyweight_monitor:62  |               10       |   Heavyweight Locked(重量级锁)
|---------------------------------------------------|--------------------|

Mark Word 信息变化过程

无锁状态

没有线程访问同步代码块,biased_lock:0

偏向锁(Biased Locking)

当第一个线程访问同步代码块时,Mark Word 记录该线程的ID,biased_lock:1

后续如果是同一个线程进入该代码块时,直接检查线程ID是否和记录的一样,一样则不需要加锁

轻量级锁(Lightweight Locking)

当有第二个线程尝试获取锁的时候,偏向锁会升级成为轻量级锁

线程在栈帧中创建 Lock Record,通过CAS算法将 Mark Word 复制到 Lock Record,并尝试用CAS将 Mark Word 替换为指向 Lock Record 的指针(ptr_to_lock_record)

若CAS成功,获得锁。此时 State: 00

重量级锁(Heavyweight Locking)

若多个线程在获取轻量级锁时,CAS操作失败,并且重试一定次数后依然没有获得锁,说明锁竞争激烈。轻量级锁升级为重量级锁

此时,JVM会在堆中创建一个 ObjectMonitor 实例(Monitor),将 Mark Word 中的内容替换为指向 Monitor 的指针(ptr_to_heavyweight_monitor)

当一个线程获得锁时,其他竞争的线程会被放入 Monitor 的 EntryList,等待操作系统级互斥锁(Mutex)的调度

  1.  线程竞争轻量级锁时,创建的Lock Record存放在线程栈帧中,对象中的 Mark Word指向的是栈帧中的Lock Record
  2. 尝试使用CAS操作竞争轻量级锁失败的线程会自旋尝试获得锁
  3. 多个线程CAS 失败超过一定次数,会升级为重量级锁,此时才会创建ObjectMonitor
  4. ObjectMonitor 并不是一开始就创建好了,是在锁升级到重量级锁的时候才创建的

绑定Monitor的流程

当锁需要升级为重量级锁时,会创建ObjectMonitor对象绑定到Mark Word,具体步骤如下:

  1. JVM创建ObjectMonitor对象(即Monitor),结构包含Owner、EntryList、WaitSet等字段。
  2. 竞争的线程尝试通过CAS操作,将Mark Word的标志位(State)从00更新到10
    1. 如果更新成功,将Mark Word替换为指向Monitor的指针,将当前线程设置为Monitor的Owner
    2. 如果更新失败,表示已经有其他线程持有锁,线程进入阻塞(竞争的线程被放入EntryList,等待操作系统调度)
  3. 线程执行完释放锁时,将Monitor中的Owner设置为null,唤醒 EntryList 或者 WaitSet 中的线程
Monitor结构
+-------------------+
|     Owner         |  -> 持有锁的线程
+-------------------+
|     EntryList     |  -> 竞争锁的线程队列(BLOCKED 状态)
+-------------------+
|     WaitSet       |  -> 调用 wait() 的线程队列(WAITING 状态)
+-------------------+

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值