当前位置:  首页>> 技术小册>> 深入拆解 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程序员提供更加丰富的并发编程能力和更加稳定的运行环境。


该分类下的相关小册推荐: