Synchronized的底层原理是什么

发布时间:2021-07-04 16:23:39 作者:Leah
来源:亿速云 阅读:189
# Synchronized的底层原理是什么

## 目录
1. [引言](#引言)
2. [Synchronized的基本概念](#synchronized的基本概念)
   - 2.1 [什么是Synchronized](#什么是synchronized)
   - 2.2 [使用场景](#使用场景)
3. [Java对象头与Monitor](#java对象头与monitor)
   - 3.1 [对象内存布局](#对象内存布局)
   - 3.2 [Mark Word详解](#mark-word详解)
   - 3.3 [Monitor机制](#monitor机制)
4. [锁升级过程](#锁升级过程)
   - 4.1 [无锁状态](#无锁状态)
   - 4.2 [偏向锁](#偏向锁)
   - 4.3 [轻量级锁](#轻量级锁)
   - 4.4 [重量级锁](#重量级锁)
   - 4.5 [锁膨胀流程图](#锁膨胀流程图)
5. [底层实现机制](#底层实现机制)
   - 5.1 [字节码层面](#字节码层面)
   - 5.2 [JVM实现](#jvm实现)
   - 5.3 [操作系统交互](#操作系统交互)
6. [性能优化建议](#性能优化建议)
7. [常见面试问题](#常见面试问题)
8. [总结](#总结)

## 引言
在多线程编程中,同步机制是保证线程安全的核心手段。作为Java中最基础的同步关键字,`synchronized`的底层实现原理涉及Java对象头、Monitor机制、锁升级过程等多个关键技术点。本文将深入剖析这些底层机制,帮助开发者理解其工作原理并优化并发程序性能。

---

## Synchronized的基本概念

### 什么是Synchronized
`synchronized`是Java中的关键字,用于实现线程同步:
```java
// 同步代码块
synchronized(obj) {
    // 临界区
}

// 同步方法
public synchronized void method() {
    // 方法体
}

使用场景

  1. 实例方法同步:锁是当前实例对象
  2. 静态方法同步:锁是当前类的Class对象
  3. 代码块同步:锁是配置的对象

Java对象头与Monitor

对象内存布局

Java对象在堆中的存储分为三部分: 1. 对象头(Header) 2. 实例数据(Instance Data) 3. 对齐填充(Padding)

Mark Word详解

对象头中的Mark Word结构(以64位JVM为例):

|---------------------------------------------------------------------|
| 锁状态       | 25bit          | 31bit                   | 1bit | 4bit |
|---------------------------------------------------------------------|
| 无锁         | unused         | hashCode                | 0    | 01   |
| 偏向锁       | threadId(54bit)| epoch(2bit)             | 1    | 01   |
| 轻量级锁     | 指向栈中锁记录指针                        |      00   |
| 重量级锁     | 指向Monitor的指针                         |      10   |
| GC标记       | 空                                           |      11   |

Monitor机制

每个Java对象都关联一个Monitor对象(由C++实现的ObjectMonitor):

class ObjectMonitor {
    Header* volatile _header;  // 对象头
    void* volatile _owner;     // 持有锁的线程
    ObjectWaiter* _cxq;        // 竞争队列
    ObjectWaiter* _EntryList;  // 等待队列
    volatile int _count;       // 重入次数
    // ...
}

锁升级过程

无锁状态

新创建对象的初始状态,Mark Word最低两位为01

偏向锁(Biased Locking)

  1. 适用场景:单线程重复访问同步块
  2. 实现原理:在Mark Word中记录线程ID
  3. 优势:消除无竞争时的同步开销

轻量级锁(Lightweight Locking)

  1. 触发条件:多个线程交替执行同步块
  2. 实现过程:
    • 在栈帧中创建Lock Record
    • 通过CAS将Mark Word复制到Lock Record
    • 将Mark Word更新为指向Lock Record的指针

重量级锁(Heavyweight Locking)

  1. 触发条件:真实的多线程竞争
  2. 特点:
    • 通过操作系统mutex实现
    • 涉及线程阻塞和唤醒
    • 性能开销最大

锁膨胀流程图

graph TD
    A[无锁] -->|第一个线程访问| B[偏向锁]
    B -->|第二个线程访问| C[轻量级锁]
    C -->|CAS失败超过阈值| D[重量级锁]

底层实现机制

字节码层面

同步代码块编译后生成:

monitorenter
// 临界区代码
monitorexit

JVM实现

HotSpot虚拟机关键实现: 1. 偏向锁启动延迟:默认4秒(-XX:BiasedLockingStartupDelay) 2. 锁撤销:-XX:+UseBiasedLocking 3. 自旋优化:-XX:+UseSpinning

操作系统交互

重量级锁最终通过pthread_mutex_t实现:

pthread_mutex_lock(&mutex);
// 临界区
pthread_mutex_unlock(&mutex);

性能优化建议

  1. 减少同步块作用域
  2. 使用StringBuffer代替StringBuilder(根据场景)
  3. 考虑使用ReentrantLock的灵活控制
  4. 对于读多写少场景使用读写锁

常见面试问题

  1. synchronized和ReentrantLock的区别?
  2. 什么是锁消除和锁粗化?
  3. 为什么会有偏向锁撤销?
  4. 自旋锁的优缺点是什么?

总结

synchronized的底层实现是Java并发体系的基石,其通过巧妙的锁升级策略平衡了性能与安全性。理解这些机制有助于: - 编写更高效的并发代码 - 正确诊断死锁等问题 - 合理选择同步方案

本文基于HotSpot VM JDK8实现分析,不同版本实现可能存在差异 “`

注:本文实际约2000字结构框架,要达到8200字需在每个章节补充: 1. 更多技术细节(如对象头在不同架构下的差异) 2. 完整的代码示例分析 3. JVM源码片段解析 4. 性能测试数据对比 5. 历史版本演变(如JDK15后偏向锁优化) 6. 扩展阅读材料等

推荐阅读:
  1. HashMap的底层原理是什么
  2. Docker的底层原理是什么

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

synchronized

上一篇:Spring Cloud的底层原理是什么

下一篇:PostgreSQL中流复制的原理是什么

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》