synchronized到底底层怎么实现?HotSpot能告诉你答案吗?

在多线程编程领域,synchronized是Java开发者最常用的线程同步工具。但许多开发者对其底层实现存在疑问:对象头如何存储锁状态?Monitor机制如何管理线程竞争?HotSpot虚拟机究竟通过哪些技术实现锁升级?本文将带您深入HotSpot源码,揭开这些核心问题的答案。

一、对象头:锁信息的存储基石

1.1 Mark Word的核心结构

每个Java对象在内存中分为三部分:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。其中对象头的Mark Word区域存储着与锁相关的关键信息:
```html

  • 25位:存储对象哈希码(未锁定时)
  • 4位:分代年龄(GC用)
  • 1位:偏向锁标志
  • 2位:锁状态标志

```
在64位JVM中,Mark Word扩展为64位结构,锁标志位控制着锁状态的实时转换。

1.2 锁状态标志位详解

标志值 锁状态
01 无锁/偏向锁
00 轻量级锁
10 重量级锁
11 GC标记

二、Monitor机制:线程同步的核心引擎

2.1 ObjectMonitor结构解析

HotSpot通过ObjectMonitor对象实现Monitor机制,其关键字段包括:
```html

  • _owner:指向持有锁的线程
  • _EntryList:锁竞争队列
  • _WaitSet:等待唤醒队列
  • _recursions:重入计数器

```

2.2 同步流程全解析

2.2.1 加锁流程(monitorenter)

  1. 检查对象头标志位
  2. 通过CAS尝试获取锁
  3. 失败后进入自适应自旋
  4. 最终进入内核态阻塞

2.2.2 释放流程(monitorexit)

  1. 递归计数器减一
  2. 唤醒EntryList中的线程
  3. 修改对象头状态

三、锁升级:性能与安全的动态平衡

3.1 偏向锁优化

当没有线程竞争时,HotSpot通过偏向锁优化,将线程ID记录在对象头中,后续同步操作直接比对线程ID即可完成。

3.2 轻量级锁的CAS机制

当出现轻度竞争时,JVM会将对象头中的锁记录指针替换为指向线程栈中的锁记录空间,通过CAS操作实现快速锁获取。

3.3 重量级锁的终极保障

当自旋超过阈值(默认10次),锁将升级为重量级锁,此时会触发操作系统级别的线程调度,确保系统稳定性。

四、HotSpot源码中的关键实现

4.1 对象头操作源码片段

在HotSpot的oop.hpp文件中,Mark Word操作的核心逻辑:

markOop header = object->mark();
if (header->is_neutral()) {
   // 尝试获取轻量级锁
}

4.2 锁升级的触发条件

  • 偏向锁:对象第一次被线程访问
  • 轻量级锁:CAS操作失败但竞争不激烈
  • 重量级锁:自适应自旋失败或存在激烈竞争

五、性能优化实践建议

5.1 减少锁竞争

  • 缩小同步代码块范围
  • 使用ThreadLocal机制
  • 采用无锁数据结构

5.2 合理控制锁粒度

通过分段锁读写锁优化,在保证线程安全的前提下提高并发性能。

总结:HotSpot的锁实现智慧

通过对象头、Monitor和锁状态机的精密协作,HotSpot实现了锁状态的动态转换线程调度的智能决策。这种分层实现的机制既保证了基本线程安全,又通过锁升级策略实现性能优化,完美平衡了安全与效率的需求。

完整代码示例与更多技术细节已上传至网盘:
下载地址(访问密码:6872)