
在Java并发编程领域,synchronized无疑是最基础也最核心的同步工具。从JDK早期的“重量级锁”标签,到JDK1.6引入锁升级机制带来的性能飞跃,再到JDK15之后对偏向锁的默认禁用,synchronized的优化从未停止。本文将基于JDK17 LTS版本,从底层对象布局、JVM源码实现几个维度,100%准确地拆解synchronized的锁升级全流程,让你彻底搞懂无锁、偏向锁、轻量级锁、重量级锁的底层逻辑,既能夯实并发编程的核心基础,也能解决生产环境中的实际并发问题。
整个synchronized锁升级机制,完全是围绕Java对象头中的Mark Word实现的,想要彻底搞懂锁升级,必须先吃透Java对象的内存布局。
在64位JVM(当前生产环境主流)开启压缩指针(-XX:+UseCompressedOops,JDK17默认开启)的情况下,Java对象在堆内存中的布局分为三个部分:
Mark Word(标记字段,8字节)、Class Pointer(类型指针,4字节,压缩后);如果是数组对象,额外增加4字节的数组长度。Mark Word是一个8字节(64位)的动态数据结构,会根据对象的运行状态复用存储空间,不同状态下的位分布完全不同,这是锁升级的核心载体。以下是64位JVM开启压缩指针后,Mark Word在不同锁状态下的权威位分布(基于OpenJDK 17源码):
锁状态 | 64位Mark Word位分布(从高位到低位) | 偏向锁标志(1位) | 锁标志(2位) |
|---|---|---|---|
无锁不可偏向 | unused(25) | identityHashCode(31) | unused(1) | 分代年龄(4) | 0 | 01 |
无锁可偏向 | thread(54) | epoch(2) | unused(1) | 分代年龄(4) | 1 | 01 |
偏向锁 | 偏向线程ID(54) | epoch(2) | unused(1) | 分代年龄(4) | 1 | 01 |
轻量级锁 | 指向线程栈Lock Record的指针(62) | 无 | 00 |
重量级锁 | 指向ObjectMonitor对象的指针(62) | 无 | 10 |
GC标记 | 空(62) | 无 | 11 |
这里必须明确两个核心判断位,也是很多技术文章的常见错误点:
01+0为无锁不可偏向,01+1为可偏向/偏向锁状态。synchronized的本质是对某个对象加锁,根据锁对象的不同,分为三种使用场景:
this,属于对象锁,不同实例的锁互不影响。Class对象,属于类锁,对该类的所有实例生效。根据JVM规范,synchronized的底层实现分为两种形式,本质都是获取对象对应的监视器锁:
monitorenter和monitorexit字节码指令实现。线程执行到monitorenter时尝试获取对象的监视器所有权,执行到monitorexit时释放所有权,编译器会保证异常时也能执行monitorexit,避免死锁。ACC_SYNCHRONIZED标志实现。JVM调用方法时会检查该标志,若开启则自动尝试获取对象的监视器锁,方法执行完毕后自动释放,语义与monitorenter/monitorexit完全一致。所有Java对象都天然关联一个ObjectMonitor监视器对象,这是重量级锁的核心载体,而偏向锁、轻量级锁不会直接初始化该对象,这也是不同锁类型的核心性能差异来源。
synchronized的锁升级是JVM为了减少同步开销而做的自适应优化,核心逻辑是:根据竞争激烈程度,从低开销锁逐步升级到高开销锁,锁的膨胀过程在持有期间是单向的,不可降级,锁完全释放后会重置为无锁状态。

无锁状态分为两种子状态,是锁升级的起点:
System.identityHashCode(),Mark Word中biased_lock=1、lock=01,线程ID、epoch字段全为0,可被第一个获取锁的线程偏向。identityHashCode(),Mark Word中biased_lock=0、lock=01,存储了对象的哈希值,无法进入偏向锁状态,获取锁时直接进入轻量级锁流程。64位JVM中,对象的identityHashCode是31位,正好占用了偏向锁状态下存储线程ID的54位空间的低31位。一旦写入哈希值,就没有足够空间存储偏向线程ID,JVM会强制禁用该对象的偏向锁,这是底层位空间冲突导致的必然结果,后续会通过代码实战验证该逻辑。
在无多线程竞争的场景下,完全消除同步操作的开销,让锁永久偏向于第一个获取它的线程。后续该线程重入同步块时,无需任何CAS操作,仅需简单的字段检查,性能几乎与无锁代码一致。
根据JEP 374规范,JDK15及以上版本默认禁用偏向锁,-XX:+UseBiasedLocking参数被标记为废弃,-XX:BiasedLockingStartupDelay默认值为0。若要开启偏向锁,需在JVM启动参数中添加:
-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0 --add-opens java.base/java.lang=ALL-UNNAMED
其中--add-opens参数用于JOL工具查看对象头,适配JDK17的模块化机制。
Mark Word的biased_lock=1、lock=01,确认处于可偏向状态。Mark Word中的线程ID字段:Mark Word。偏向锁的撤销是较重的操作,需要等待全局安全点(STW),暂停所有持有该锁的线程,检查持有偏向锁的线程状态:
Mark Word重置为无锁可偏向状态。Displaced Mark Word写入线程的Lock Record,Mark Word改为指向Lock Record的指针,lock位改为00。Mark Word重置为无锁可偏向状态,完成撤销。为了避免大量对象的偏向锁频繁撤销导致的STW开销,JVM引入了批量优化机制:
-XX:BiasedLockingBulkRebiasThreshold(默认20),JVM会给该类的epoch字段加1,所有该类对象的偏向锁需重新偏向,解决同类型对象在多线程间交替使用导致的频繁撤销问题。-XX:BiasedLockingBulkRevokeThreshold(默认40),JVM会判定该类存在持续的多线程竞争,直接禁用该类所有对象的偏向锁,后续创建的该类对象均为不可偏向状态。在多线程交替使用锁、无同时竞争的场景下,避免重量级锁的用户态与内核态切换开销,基于线程栈帧中的Lock Record和CAS操作实现,属于用户态自旋锁,开销远小于重量级锁。
Lock Record空间,用于存储对象当前Mark Word的拷贝,该拷贝称为Displaced Mark Word。Mark Word替换为指向当前线程栈帧中Lock Record的指针。Mark Word的lock位设置为00,执行同步代码。JDK17中的自旋锁是完全自适应的,JVM会根据前一次在同一个锁上的自旋时间、锁持有者的状态,动态调整自旋次数:
Lock Record中存储的Displaced Mark Word写回对象的Mark Word。轻量级锁适用于多线程交替执行同步块、锁持有时间短、无同时竞争的场景。若多个线程同时竞争锁,轻量级锁的自旋会消耗大量CPU资源,性能反而会急剧下降,此时JVM会将锁升级为重量级锁。
在多线程同时激烈竞争锁的场景下,通过操作系统的互斥量(mutex)实现同步,避免CPU空转,保证线程安全。
重量级锁的底层是ObjectMonitor对象,其核心结构来自OpenJDK 17源码:
_owner:指向当前持有锁的线程。_EntryList:竞争锁失败的线程进入该队列,处于BLOCKED阻塞状态。_WaitSet:调用了wait()方法的线程进入该队列,处于WAITING等待状态。_count:锁的重入次数。_recursions:锁的重入深度。ObjectMonitor对象,将对象的Mark Word设置为指向ObjectMonitor的指针,lock位改为10。ObjectMonitor的_EntryList队列,线程状态从RUNNABLE变为BLOCKED,操作系统将线程挂起,发生用户态到内核态的切换。_EntryList中唤醒一个线程,重新竞争锁。_count和_recursions字段会记录重入次数,释放时需对应次数的monitorexit,直到_count为0,锁才会真正释放。重量级锁的核心开销来自用户态与内核态的切换,线程的阻塞和唤醒需要操作系统内核完成,涉及进程上下文的保存和恢复,开销极大。因此重量级锁适用于锁持有时间长、竞争激烈的场景,此时切换开销远小于CPU空转的开销。
以下所有代码均基于JDK17编写,用于验证上述锁升级的核心原理。
采用所有组件的最新稳定版本,符合生产环境规范:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.jam</groupId>
<artifactId>synchronized-demo</artifactId>
<version>1.0.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<lombok.version>1.18.34</lombok.version>
<jol.version>0.17</jol.version>
<slf4j.version>2.0.12</slf4j.version>
<logback.version>1.5.6</logback.version>
<spring.version>6.1.15</spring.version>
<fastjson2.version>2.0.52</fastjson2.version>
<guava.version>33.1.0-jre</guava.version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>${jol.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>${fastjson2.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
package com.jam.demo;
import lombok.extern.slf4j.Slf4j;
import org.openjdk.jol.info.ClassLayout;
import org.springframework.util.ObjectUtils;
/**
* 无锁状态对象头验证示例
*
* @author ken
* @date 2026-03-05
*/
@Slf4j
publicclass NoLockDemo {
privatestaticfinal Object LOCK_OBJECT = new Object();
public static void main(String[] args) {
log.info("===== 刚创建的对象,无锁状态 =====");
printObjectHeader(LOCK_OBJECT);
log.info("===== 调用identityHashCode()之后的对象头 =====");
int identityHashCode = System.identityHashCode(LOCK_OBJECT);
log.info("对象的identityHashCode: {}", Integer.toHexString(identityHashCode));
printObjectHeader(LOCK_OBJECT);
}
/**
* 打印对象头信息
*
* @param obj 待打印的对象
*/
private static void printObjectHeader(Object obj) {
if (ObjectUtils.isEmpty(obj)) {
log.error("打印对象头失败,对象为空");
return;
}
String classLayout = ClassLayout.parseInstance(obj).toPrintable();
log.info("\n{}", classLayout);
}
}
运行说明:需添加JVM参数--add-opens java.base/java.lang=ALL-UNNAMED,运行后可观察到:刚创建的对象Mark Word的偏向锁标志位,调用identityHashCode后,哈希值被写入Mark Word,偏向锁标志位变为0,对象进入不可偏向状态。
package com.jam.demo;
import lombok.extern.slf4j.Slf4j;
import org.openjdk.jol.info.ClassLayout;
import org.springframework.util.ObjectUtils;
/**
* 偏向锁状态验证示例
* 需添加JVM启动参数:-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0 --add-opens java.base/java.lang=ALL-UNNAMED
*
* @author ken
* @date 2026-03-05
*/
@Slf4j
publicclass BiasedLockDemo {
privatestaticfinal Object LOCK_OBJECT = new Object();
public static void main(String[] args) throws InterruptedException {
log.info("===== 刚创建的对象,可偏向无锁状态 =====");
printObjectHeader(LOCK_OBJECT);
log.info("===== 主线程第一次获取锁,偏向锁获取 =====");
synchronized (LOCK_OBJECT) {
printObjectHeader(LOCK_OBJECT);
}
log.info("===== 主线程释放锁之后,偏向锁状态保持 =====");
printObjectHeader(LOCK_OBJECT);
log.info("===== 主线程第二次重入锁,偏向锁重入 =====");
synchronized (LOCK_OBJECT) {
printObjectHeader(LOCK_OBJECT);
}
log.info("===== 新线程竞争锁,触发偏向锁撤销 =====");
Thread thread = new Thread(() -> {
synchronized (LOCK_OBJECT) {
log.info("===== 新线程获取锁,锁升级为轻量级锁 =====");
printObjectHeader(LOCK_OBJECT);
}
});
thread.start();
thread.join();
log.info("===== 偏向锁撤销后,对象最终状态 =====");
printObjectHeader(LOCK_OBJECT);
}
/**
* 打印对象头信息
*
* @param obj 待打印的对象
*/
private static void printObjectHeader(Object obj) {
if (ObjectUtils.isEmpty(obj)) {
log.error("打印对象头失败,对象为空");
return;
}
String classLayout = ClassLayout.parseInstance(obj).toPrintable();
log.info("\n{}", classLayout);
}
}
运行结果:开启偏向锁后,主线程第一次获取锁时,Mark Word中写入主线程ID,进入偏向锁状态;释放锁后偏向锁状态保持,重入无额外开销;新线程竞争锁触发偏向锁撤销,锁升级为轻量级锁,lock位变为00。
package com.jam.demo;
import lombok.extern.slf4j.Slf4j;
import org.openjdk.jol.info.ClassLayout;
import org.springframework.util.ObjectUtils;
/**
* 轻量级锁状态验证示例
* 需添加JVM启动参数:--add-opens java.base/java.lang=ALL-UNNAMED
*
* @author ken
* @date 2026-03-05
*/
@Slf4j
publicclass LightweightLockDemo {
privatestaticfinal Object LOCK_OBJECT = new Object();
privatestaticint count = 0;
public static void main(String[] args) throws InterruptedException {
log.info("===== 初始无锁状态 =====");
printObjectHeader(LOCK_OBJECT);
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
synchronized (LOCK_OBJECT) {
count++;
log.info("线程1执行同步代码,当前count: {}", count);
if (i == 2) {
log.info("===== 线程1持有锁,轻量级锁状态 =====");
printObjectHeader(LOCK_OBJECT);
}
}
}
}, "thread-1");
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
synchronized (LOCK_OBJECT) {
count++;
log.info("线程2执行同步代码,当前count: {}", count);
if (i == 2) {
log.info("===== 线程2持有锁,轻量级锁状态 =====");
printObjectHeader(LOCK_OBJECT);
}
}
}
}, "thread-2");
thread1.start();
thread1.join();
thread2.start();
thread2.join();
log.info("===== 所有线程执行完毕,最终count: {}, 锁状态 =====", count);
printObjectHeader(LOCK_OBJECT);
}
/**
* 打印对象头信息
*
* @param obj 待打印的对象
*/
private static void printObjectHeader(Object obj) {
if (ObjectUtils.isEmpty(obj)) {
log.error("打印对象头失败,对象为空");
return;
}
String classLayout = ClassLayout.parseInstance(obj).toPrintable();
log.info("\n{}", classLayout);
}
}
运行结果:两个线程交替执行同步代码,无同时竞争,锁保持轻量级锁状态,lock位为00,Mark Word中存储指向持有锁线程栈帧中Lock Record的指针。
package com.jam.demo;
import lombok.extern.slf4j.Slf4j;
import org.openjdk.jol.info.ClassLayout;
import org.springframework.util.ObjectUtils;
import java.util.concurrent.CountDownLatch;
/**
* 重量级锁状态验证示例
* 需添加JVM启动参数:--add-opens java.base/java.lang=ALL-UNNAMED
*
* @author ken
* @date 2026-03-05
*/
@Slf4j
publicclass HeavyweightLockDemo {
privatestaticfinal Object LOCK_OBJECT = new Object();
privatestaticint count = 0;
privatestaticfinalint THREAD_COUNT = 10;
privatestaticfinalint LOOP_COUNT = 1000;
public static void main(String[] args) throws InterruptedException {
CountDownLatch startLatch = new CountDownLatch(1);
CountDownLatch endLatch = new CountDownLatch(THREAD_COUNT);
log.info("===== 初始无锁状态 =====");
printObjectHeader(LOCK_OBJECT);
for (int i = 0; i < THREAD_COUNT; i++) {
new Thread(() -> {
try {
startLatch.await();
for (int j = 0; j < LOOP_COUNT; j++) {
synchronized (LOCK_OBJECT) {
count++;
if (count == 5000) {
log.info("===== 多线程激烈竞争,锁升级为重量级锁 =====");
printObjectHeader(LOCK_OBJECT);
}
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("线程执行异常", e);
} finally {
endLatch.countDown();
}
}, "thread-" + i).start();
}
startLatch.countDown();
endLatch.await();
log.info("===== 所有线程执行完毕,最终count: {}, 锁最终状态 =====", count);
printObjectHeader(LOCK_OBJECT);
}
/**
* 打印对象头信息
*
* @param obj 待打印的对象
*/
private static void printObjectHeader(Object obj) {
if (ObjectUtils.isEmpty(obj)) {
log.error("打印对象头失败,对象为空");
return;
}
String classLayout = ClassLayout.parseInstance(obj).toPrintable();
log.info("\n{}", classLayout);
}
}
运行结果:10个线程同时竞争锁,自适应自旋快速失败,锁升级为重量级锁,lock位变为10,Mark Word中存储指向ObjectMonitor对象的指针,最终count值为10000,保证线程安全。
package com.jam.demo;
import lombok.extern.slf4j.Slf4j;
import org.openjdk.jol.info.ClassLayout;
import org.springframework.util.ObjectUtils;
/**
* 调用identityHashCode后偏向锁失效验证示例
* 需添加JVM启动参数:-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0 --add-opens java.base/java.lang=ALL-UNNAMED
*
* @author ken
* @date 2026-03-05
*/
@Slf4j
publicclass BiasedLockInvalidDemo {
privatestaticfinal Object LOCK_OBJECT_1 = new Object();
privatestaticfinal Object LOCK_OBJECT_2 = new Object();
public static void main(String[] args) {
log.info("===== 锁对象1:刚创建,可偏向状态 =====");
printObjectHeader(LOCK_OBJECT_1);
log.info("===== 锁对象1:获取锁,进入偏向锁状态 =====");
synchronized (LOCK_OBJECT_1) {
printObjectHeader(LOCK_OBJECT_1);
}
log.info("===== 锁对象2:刚创建,可偏向状态 =====");
printObjectHeader(LOCK_OBJECT_2);
log.info("===== 锁对象2:调用identityHashCode =====");
int identityHashCode = System.identityHashCode(LOCK_OBJECT_2);
log.info("锁对象2的identityHashCode: {}", Integer.toHexString(identityHashCode));
printObjectHeader(LOCK_OBJECT_2);
log.info("===== 锁对象2:获取锁,无法进入偏向锁,直接进入轻量级锁 =====");
synchronized (LOCK_OBJECT_2) {
printObjectHeader(LOCK_OBJECT_2);
}
}
/**
* 打印对象头信息
*
* @param obj 待打印的对象
*/
private static void printObjectHeader(Object obj) {
if (ObjectUtils.isEmpty(obj)) {
log.error("打印对象头失败,对象为空");
return;
}
String classLayout = ClassLayout.parseInstance(obj).toPrintable();
log.info("\n{}", classLayout);
}
}
运行结果:锁对象1正常进入偏向锁状态;锁对象2调用identityHashCode后,偏向锁标志位变为0,获取锁时直接进入轻量级锁状态,验证了位空间冲突导致偏向锁失效的核心原理。
这是最常见的认知错误。准确结论是:锁的膨胀过程在持有期间是单向的,只能从低级别升级到高级别,不可降级;但当锁完全释放后,对象的Mark Word会被重置为无锁状态,下一次竞争会重新开始锁升级流程。例如,一个对象的锁升级为重量级锁后,当所有线程都释放锁,对象会回到无锁状态,下一次线程获取锁时,会重新从偏向锁(开启时)或轻量级锁开始。
锁类型 | 核心实现 | 适用场景 | 性能开销 | 线程安全保障 |
|---|---|---|---|---|
偏向锁 | Mark Word存储偏向线程ID,无CAS操作 | 单线程长期使用锁,无多线程竞争 | 几乎为0,与无锁代码一致 | 无竞争下线程安全 |
轻量级锁 | 线程栈帧Lock Record + 自适应CAS自旋 | 多线程交替使用锁,持有时间短,无同时竞争 | 用户态CAS操作,开销小,自旋失败消耗CPU | 交替竞争下线程安全 |
重量级锁 | 操作系统互斥量mutex + ObjectMonitor | 多线程同时激烈竞争,锁持有时间长 | 用户态与内核态切换,开销极大 | 激烈竞争下线程安全 |
轻量级锁获取失败后会采用自旋重试,但自旋锁不等于轻量级锁。自旋是一种获取锁的重试机制,不仅轻量级锁会使用,重量级锁在进入阻塞之前也会尝试自旋。轻量级锁的核心是基于Lock Record的CAS操作,自旋是其竞争失败后的优化手段。
synchronized修饰实例方法、synchronized(this)均为对象锁。Class对象,一个类仅有一个Class对象,因此类锁对该类的所有实例生效,synchronized修饰静态方法、synchronized(XXX.class)均为类锁。这三个方法均基于ObjectMonitor实现:调用wait()会释放锁并将线程加入WaitSet队列,调用notify()会唤醒WaitSet中的线程,这些操作都必须先持有对象的监视器锁。若不在同步块中调用,JVM会抛出IllegalMonitorStateException异常,这是JVM规范的强制要求,也是为了保证线程间通信的原子性和线程安全。
在保证线程安全的前提下,尽量缩小锁的范围,仅对需要同步的共享变量操作加锁,不要对整个方法加锁,减少锁的持有时间,降低竞争概率,避免锁快速升级为重量级锁。
synchronized,内部包含大量非线程安全的耗时IO操作。同步块中若包含IO操作、网络调用、数据库查询等耗时操作,会导致锁持有时间大幅增加,多线程竞争概率急剧上升,锁会快速升级为重量级锁,性能严重下降。若必须执行耗时操作,尽量将其移出同步块。
private final修饰的自定义对象,保证锁的封装性,避免外部代码获取锁对象导致死锁。String、Integer等包装类型作为锁对象,常量池缓存会导致锁对象被复用,引发非预期的线程安全问题。this作为锁对象,外部代码可获取到该实例,存在死锁风险。JIT编译器会对synchronized做两项核心优化,可通过合理编码提升优化效果:
tryLock超时时间,避免无限期等待。Mark Word实现,流程如下:Mark Word,锁偏向于该线程,后续重入无需任何同步操作,开销极小。Lock Record,通过CAS将对象的Mark Word替换为指向Lock Record的指针,获取成功则持有锁,失败则进入自适应自旋。ObjectMonitor实现;ReentrantLock是JDK层面的API,基于AQS抽象队列同步器实现。Condition,synchronized仅支持一个wait/notify队列。identityHashCode是31位,正好占用了偏向锁状态下存储偏向线程ID的54位空间的低31位。一旦调用identityHashCode,Mark Word中会写入31位哈希值,没有足够空间存储偏向线程ID,因此JVM会强制禁用该对象的偏向锁,后续该对象获取锁时会直接进入轻量级锁流程。Lock Record数量记录重入次数,每重入一次创建一个新的Lock Record,释放时依次移除,直到所有Lock Record都被移除,锁才真正释放。ObjectMonitor中的_count和_recursions字段记录重入次数,线程每重入一次,计数器加1,释放时减1,直到计数器为0,锁才真正释放。synchronized是Java并发编程的基石,锁升级机制是其性能优化的核心。只有彻底理解其底层实现原理,才能写出高效、安全的并发代码,从根源上规避生产环境中的并发问题。