Synchronized原理最全详解(图文全面总结)

Synchronized原理最全详解(图文全面总结)

Synchronized是实现多线程同步的机制,但是很多对Synchronized原理并不了解,本篇详解Synchronized原理@mikechen

Synchronized原理

Synchronized 是 Java 中用于实现同步的一种内置机制,可以用于方法、和代码块。

public class SynchronizedExample {
    
    // 同步实例方法
    public synchronized void instanceMethod() {
        // 线程安全的代码
    }
    
    // 同步静态方法
    public synchronized static void staticMethod() {
        // 线程安全的代码
    }
    
    // 同步代码块
    public void codeBlock() {
        Object lock = new Object();
        synchronized (lock) {
            // 线程安全的代码
        }
    }
}

确保同一时刻只有一个线程可以执行被 synchronized 修饰的代码,从而避免线程间的数据不一致问题。

Synchronized的实现原理:主要涉及 Java 对象头、Monitor监视器对象………等。

 

Java对象头

Java 中的每个对象在内存中,都包含对象头(Object Header),对象头存储了对象的运行时数据。

整体结构,如下图所示:

Synchronized原理最全详解(图文全面总结)

对象头主要由两部分组成:

  1. Mark Word(标记字段):存储对象的运行时数据,如哈希码、GC 分代年龄、锁状态等。
  2. Class Pointer(类型指针):指向对象的类元数据,确定对象的类型信息。
  3. 数组长度(可选):如果对象是数组类型,还会包含一个用于存储数组长度的字段。

比如:在64位操作系统中,对象头结构如下:

组成部分 大小(字节) 描述
Mark Word 8 存储对象的哈希码、GC 信息、锁状态等
Class Pointer 8 指向类元数据的指针
数组长度(可选) 4 或 8 数组类型对象的长度信息

 

Monitor监视器

在 Java 中,synchronized 的底层实现依赖于 Monitor(监视器)。

Monitor 是一种同步工具,用于管理多线程对共享资源的访问,每个 Java 对象都有一个与之关联的 Monitor。

当一个线程获得对象的 Monitor 时,其他试图获得该 Monitor 的线程将被阻塞,直到持有 Monitor 的线程释放它。

synchronized 关键字在编译后,会在对应的位置插入 monitorenter 、和 monitorexit 字节码指令,分别在进入和退出同步块时执行。

如下图所示:

Synchronized原理最全详解(图文全面总结)

大致流程,如下:

  1. 当线程进入 synchronized 方法、或代码块时,需要先获得对应对象的 Monitor,比如:上图的红色的:monitorenter。
  2. 尝试获取对象的 Monitor,如果成功,程序继续执行,否则,线程进入阻塞状态。
  3. 如果 Monitor 未被占用,线程将成功获得锁,进入临界区。
  4. 如果 Monitor 已被其他线程占用,当前线程将进入阻塞状态,加入到 EntryList 中。
  5. 线程在退出 synchronized 方法、或代码块时,释放 Monitor,唤醒在 EntryList 中等待的线程。

 

Synchronized锁升级

为了提高锁的性能,Java 在 JDK 1.6 引入了锁升级机制,锁可以在不同的状态之间升级,以适应不同的并发场景。

如下图所示:

Synchronized原理最全详解(图文全面总结)

完整的锁升级流程:

1.无锁状态

对象刚创建时,没有任何锁。

2.偏向锁

第一个线程访问同步块,获取偏向锁。

偏向锁的意思是,锁会偏向于第一个获得它的线程,如果该锁在之后的执行中没有被其他线程获取,那么持有锁的线程在进入和退出同步块时不需要进行同步操作。

后续相同线程再次进入同步块,无需任何同步操作。

当有其他线程尝试获取该锁时,撤销偏向锁,升级为轻量级锁。

3.轻量级锁

线程尝试使用 CAS 操作获取锁,自旋等待。

如果自旋成功,获取锁。

如果自旋失败,或者锁竞争激烈,升级为重量级锁。

轻量级锁:是在偏向锁的基础上,为了解决线程间的短暂锁竞争而设计的,相比重量级锁,轻量级锁在竞争不激烈的情况下性能更好。

4.重量级锁

线程获取锁失败,被阻塞,进入等待队列。

持有锁的线程释放锁后,唤醒等待队列中的线程,重新竞争锁。

作者简介

陈睿|mikechen,10年+大厂架构经验,BAT资深面试官,就职于阿里巴巴、淘宝、百度等一线互联网大厂。

关注作者「mikechen」公众号,获取更多技术干货!

后台回复架构,即可获取《阿里架构师进阶专题全部合集》,后台回复面试即可获取《史上最全阿里Java面试题总结

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧