问答题1021/1053说说synchronized的实现原理

难度:
2021-11-02 创建

参考答案:

synchronized 是 Java 中一种用于保证线程安全的机制,它通过加锁的方式来控制对共享资源的访问。它的实现原理基于 监视器锁(Monitor Lock)和 对象头,通过加锁和解锁来确保同一时刻只有一个线程可以执行被 synchronized 修饰的代码块或方法。

synchronized 实现原理

  1. 对象头和监视器锁

    • 每个 Java 对象都有一个与之关联的对象头,Java 虚拟机将对象头分为两部分:Mark Word 和 Klass Pointer。Mark Word 存储着对象的哈希码、GC信息、锁状态等。
    • 在 Java 中,synchronized 锁是通过对象的监视器(monitor)来实现的。每个对象都对应一个监视器,监视器的管理由 JVM 提供。通过监视器来控制线程的访问,保证在同一时刻只有一个线程能访问同步代码块或方法。
  2. 锁的获取与释放

    • 当一个线程访问被 synchronized 修饰的方法或代码块时,首先需要获得对象的锁。若其他线程已经持有该锁,当前线程将进入阻塞状态,直到锁被释放。
    • 线程获取锁时,会通过修改对象头中的锁标志位来标记该对象的状态。JVM 使用对象头中的标志位来管理不同的锁状态(如无锁、偏向锁、轻量级锁、重量级锁等)。
  3. 锁的升级与降级

    • 偏向锁:线程首次获取锁时,JVM 会首先尝试为该锁分配偏向锁,偏向锁会将锁的标志指向当前线程 ID,表示当前线程对该对象拥有锁的偏向。如果线程后续继续访问该对象,则无需再竞争锁。
    • 轻量级锁:如果锁已经被其他线程持有,JVM 会尝试通过原子操作(CAS)来获取轻量级锁。轻量级锁通过在对象头中使用 CAS 操作来尝试获取锁,不会阻塞当前线程。轻量级锁是为了减少线程间的竞争,提高性能。
    • 重量级锁:当多线程竞争轻量级锁失败,或者轻量级锁升级失败时,JVM 会将锁升级为重量级锁。重量级锁涉及操作系统的原子操作,线程会被阻塞,直到获取锁为止。
  4. 内存可见性保证

    • synchronized 还确保了内存的可见性。当一个线程释放锁时,所有它所做的修改会被刷新到主内存中,其他线程在获得该锁时,能看到这些修改。这样就保证了共享数据的可见性和一致性。
    • 同时,synchronized 还会保证在加锁区域内,所有操作的原子性,避免了多个线程同时修改共享数据的问题。
  5. JVM中的锁优化

    • JVM 会根据线程的竞争情况动态地调整锁的实现。例如,synchronized 使用时,JVM 会使用 自旋锁 来避免频繁的线程阻塞/唤醒操作,减少线程切换的开销。
    • 如果某个线程获取锁后执行时间很短,JVM 会尝试通过自旋来减少线程的上下文切换,降低性能损耗。

锁的不同状态:

synchronized 实现的锁具有不同的状态,用来表示锁的竞争情况:

  1. 无锁状态:对象没有任何线程持有锁,可以被任何线程获取。
  2. 偏向锁:一个线程持有锁并且没有其他线程竞争时,锁会变为偏向锁。偏向锁的目的是提高性能,减少锁的竞争。
  3. 轻量级锁:多个线程竞争时,JVM 会通过 CAS(Compare-And-Swap)操作来尝试获取锁,但不会阻塞线程。轻量级锁的目的是减少线程间的竞争,提高性能。
  4. 重量级锁:当多个线程竞争激烈时,JVM 会将锁提升为重量级锁。此时,线程会进入阻塞状态,直到获取锁。重量级锁涉及操作系统的调度和线程上下文切换,性能较差。

最近更新时间:2024-12-09