
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),对象头存储了对象的运行时数据。
整体结构,如下图所示:

对象头主要由两部分组成:
- Mark Word(标记字段):存储对象的运行时数据,如哈希码、GC 分代年龄、锁状态等。
- Class Pointer(类型指针):指向对象的类元数据,确定对象的类型信息。
- 数组长度(可选):如果对象是数组类型,还会包含一个用于存储数组长度的字段。
比如:在64位操作系统中,对象头结构如下:
| 组成部分 | 大小(字节) | 描述 |
|---|---|---|
| Mark Word | 8 | 存储对象的哈希码、GC 信息、锁状态等 |
| Class Pointer | 8 | 指向类元数据的指针 |
| 数组长度(可选) | 4 或 8 | 数组类型对象的长度信息 |
Monitor监视器
在 Java 中,synchronized 的底层实现依赖于 Monitor(监视器)。
Monitor 是一种同步工具,用于管理多线程对共享资源的访问,每个 Java 对象都有一个与之关联的 Monitor。
当一个线程获得对象的 Monitor 时,其他试图获得该 Monitor 的线程将被阻塞,直到持有 Monitor 的线程释放它。
synchronized 关键字在编译后,会在对应的位置插入 monitorenter 、和 monitorexit 字节码指令,分别在进入和退出同步块时执行。
如下图所示:

大致流程,如下:
- 当线程进入
synchronized方法、或代码块时,需要先获得对应对象的 Monitor,比如:上图的红色的:monitorenter。 - 尝试获取对象的 Monitor,如果成功,程序继续执行,否则,线程进入阻塞状态。
- 如果 Monitor 未被占用,线程将成功获得锁,进入临界区。
- 如果 Monitor 已被其他线程占用,当前线程将进入阻塞状态,加入到 EntryList 中。
- 线程在退出
synchronized方法、或代码块时,释放 Monitor,唤醒在 EntryList 中等待的线程。
Synchronized锁升级
为了提高锁的性能,Java 在 JDK 1.6 引入了锁升级机制,锁可以在不同的状态之间升级,以适应不同的并发场景。
如下图所示:

完整的锁升级流程:
1.无锁状态
对象刚创建时,没有任何锁。
2.偏向锁
第一个线程访问同步块,获取偏向锁。
偏向锁的意思是,锁会偏向于第一个获得它的线程,如果该锁在之后的执行中没有被其他线程获取,那么持有锁的线程在进入和退出同步块时不需要进行同步操作。
后续相同线程再次进入同步块,无需任何同步操作。
当有其他线程尝试获取该锁时,撤销偏向锁,升级为轻量级锁。
3.轻量级锁
线程尝试使用 CAS 操作获取锁,自旋等待。
如果自旋成功,获取锁。
如果自旋失败,或者锁竞争激烈,升级为重量级锁。
轻量级锁:是在偏向锁的基础上,为了解决线程间的短暂锁竞争而设计的,相比重量级锁,轻量级锁在竞争不激烈的情况下性能更好。
4.重量级锁
线程获取锁失败,被阻塞,进入等待队列。
持有锁的线程释放锁后,唤醒等待队列中的线程,重新竞争锁。
作者简介
陈睿|mikechen,10年+大厂架构经验,BAT资深面试官,就职于阿里巴巴、淘宝、百度等一线互联网大厂。
关注作者「mikechen」公众号,获取更多技术干货!
后台回复【架构】,即可获取《阿里架构师进阶专题全部合集》,后台回复【面试】即可获取《史上最全阿里Java面试题总结》