首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
01 | Java代码是怎么运行的?
02 | Java的基本类型
03 | Java虚拟机是如何加载Java类的?
04 | JVM是如何执行方法调用的?(上)
05 | JVM是如何执行方法调用的?(下)
06 | JVM是如何处理异常的?
07 | JVM是如何实现反射的?
08 | JVM是怎么实现invokedynamic的?(上)
09 | JVM是怎么实现invokedynamic的?(下)
10 | Java对象的内存布局
11 | 垃圾回收(上)
12 | 垃圾回收(下)
13 | Java内存模型
14 | Java虚拟机是怎么实现synchronized的?
15 | Java语法糖与Java编译器
16 | 即时编译(上)
17 | 即时编译(下)
18 | 即时编译器的中间表达形式
19 | Java字节码(基础篇)
20 | 方法内联(上)
21 | 方法内联(下)
22 | HotSpot虚拟机的intrinsic
23 | 逃逸分析
24 | 字段访问相关优化
25 | 循环优化
26 | 向量化
27 | 注解处理器
28 | 基准测试框架JMH(上)
29 | 基准测试框架JMH(下)
30 | Java虚拟机的监控及诊断工具(命令行篇)
31 | Java虚拟机的监控及诊断工具(GUI篇)
32 | JNI的运行机制
33 | Java Agent与字节码注入
34 | Graal:用Java编译Java
35 | Truffle:语言实现框架
36 | SubstrateVM:AOT编译框架
当前位置:
首页>>
技术小册>>
深入拆解 Java 虚拟机
小册名称:深入拆解 Java 虚拟机
### 章节 14 | Java虚拟机是怎么实现synchronized的? 在Java的世界中,`synchronized`关键字扮演着多线程并发控制的核心角色,它确保了同一时刻只有一个线程可以执行某个方法或代码块,从而避免了多线程环境下的数据不一致问题。Java虚拟机(JVM)通过一系列复杂的机制来实现`synchronized`的功能,这些机制既涉及底层的锁机制,也包含高级别的优化技术。本章节将深入剖析JVM是如何实现`synchronized`的,涵盖其基本原理、锁的类型、锁的膨胀与升级、以及相关的性能优化策略。 #### 1. synchronized的基本原理 `synchronized`关键字可以应用于方法或代码块上。当应用于方法时,它会自动作用于整个方法体;当应用于代码块时,它作用于括号内的代码。无论是哪种情况,`synchronized`都依赖于一个锁(Lock)来控制多线程的访问。 - **对象锁(Object Monitor)**:在JVM中,每个Java对象都可以关联一个监视器(Monitor),也可以被称为对象锁。当线程进入`synchronized`方法或代码块时,它会尝试获取该对象的锁。如果锁已被其他线程持有,则当前线程将阻塞,直到锁被释放。 - **类锁(Class Lock)**:对于静态`synchronized`方法,锁是与该类的Class对象相关联的。这意味着所有访问该静态`synchronized`方法的线程都将争夺同一个锁。 #### 2. 锁的类型与实现 JVM中`synchronized`的实现依赖于几种不同类型的锁,这些锁在性能和行为上各有特点。 - **偏向锁(Biased Locking)**:这是JVM在Java 6中引入的一种锁优化机制。它假设在大多数情况下,锁不会被多个线程同时竞争,因此当一个线程首次访问同步代码块并获取锁时,JVM会将其标记为偏向锁,并记录持有锁的线程ID。在后续访问中,只要该线程再次进入同步代码块,JVM就会直接放行,无需再次进行锁竞争,从而提高了效率。 - **轻量级锁(Lightweight Locking)**:如果偏向锁失败(例如,发生了线程竞争),JVM会尝试将锁升级为轻量级锁。轻量级锁通过CAS(Compare-And-Swap)操作来尝试获取锁,避免了使用重量级锁(即传统的对象监视器)带来的性能开销。如果CAS操作成功,线程将成功获取锁;如果失败,则可能意味着存在多个线程竞争锁,此时锁会进一步升级。 - **重量级锁(Heavyweight Locking)**:当轻量级锁升级失败时,JVM会最终将锁升级为重量级锁,即传统的对象监视器锁。在重量级锁状态下,线程竞争锁时会阻塞,直到持有锁的线程释放锁。虽然重量级锁保证了线程安全,但其性能开销较大。 #### 3. 锁的膨胀与升级过程 JVM中的`synchronized`锁会根据实际运行情况自动进行膨胀和升级,以适应不同的并发场景。 - **无锁状态**:初始状态,没有线程访问同步代码块。 - **偏向锁状态**:当第一个线程访问同步代码块时,锁被设置为偏向锁,并记录持有锁的线程ID。 - **轻量级锁状态**:当发生锁竞争,且竞争线程数量较少时,锁会升级为轻量级锁,通过CAS操作尝试获取锁。 - **重量级锁状态**:如果轻量级锁竞争激烈,锁会进一步升级为重量级锁,此时线程竞争锁时会发生阻塞。 #### 4. 性能优化策略 为了提升`synchronized`的性能,JVM提供了一系列优化策略: - **自旋锁(Spinning)**:在轻量级锁升级为重量级锁之前,JVM会尝试使用自旋锁来避免线程阻塞。自旋锁让线程在获取锁之前执行一个空循环(即“自旋”),如果在这段时间内锁被释放,则线程可以直接获取锁,避免了线程阻塞和唤醒的开销。 - **适应性自旋(Adaptive Spinning)**:自旋锁的一个改进版本,它会根据之前自旋成功和失败的次数动态调整自旋的时间,以提高自旋的效率。 - **锁消除(Lock Elimination)**:JVM在JIT编译过程中会分析锁的使用情况,如果发现某些锁是多余的(例如,在不会发生线程竞争的代码块中使用`synchronized`),则会在编译时直接消除这些锁,以提高性能。 - **锁粗化(Lock Coarsening)**:与锁消除相反,锁粗化是将多个连续的细粒度锁合并为单个粗粒度锁,以减少线程切换的开销。 #### 5. 总结 Java虚拟机通过一系列复杂的锁机制和优化策略实现了`synchronized`关键字的功能,确保了多线程环境下的数据安全。从偏向锁、轻量级锁到重量级锁,JVM根据实际的并发情况动态调整锁的类型,以达到性能和安全的最佳平衡。同时,通过自旋锁、锁消除、锁粗化等优化技术,进一步提升了`synchronized`的性能。理解这些机制不仅有助于我们编写更高效的多线程程序,也为我们解决多线程并发问题提供了有力的工具。 在未来的Java版本中,随着并发技术的不断发展和JVM内部机制的持续优化,我们有理由相信`synchronized`的实现将会变得更加高效和智能,为Java程序员提供更加丰富的并发编程能力和更加稳定的运行环境。
上一篇:
13 | Java内存模型
下一篇:
15 | Java语法糖与Java编译器
该分类下的相关小册推荐:
SpringBoot合辑-初级篇
Java并发编程实战
Java语言基础14-枚举和注解
Mybatis合辑5-注解、扩展、SQL构建
java源码学习笔记
Java并发编程
Java性能调优实战
Java语言基础10-Java中的集合
Java语言基础8-Java多线程
Java语言基础3-流程控制
JAVA 函数式编程入门与实践
Java必知必会-JDBC