news 2026/5/1 6:09:12

Java中synchronized和ReentrantLock锁的实现原理详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java中synchronized和ReentrantLock锁的实现原理详解

本篇博文我将通过对比来深入理解synchronizedReentrantLock在操作系统层面的实现机制。

一、整体对比概览

特性synchronizedReentrantLock
底层原语Monitor(JVM内置) + 互斥锁AQS(AbstractQueuedSynchronizer) + 互斥锁
最终系统调用futex(Linux)或类似futex(Linux)或类似
阻塞实现内核态阻塞队列内核态阻塞队列
公平性非公平(JVM实现决定)可选公平/非公平
性能差异来源JVM优化(锁升级)算法优化(CAS自旋策略)

二、底层实现架构对比

1.synchronized的实现栈

Java synchronized代码 ↓ JVM的ObjectMonitor(C++实现) ↓ os::PlatformMonitor(平台相关封装) ↓ pthread_mutex_t / futex(Linux) ↓ sys_futex系统调用 ↓ 内核调度器管理线程阻塞队列

2.ReentrantLock的实现栈

Java ReentrantLock.lock() ↓ AbstractQueuedSynchronizer.acquire(1) ↓ tryAcquire() ← FairSync/NonfairSync ↓ Unsafe.compareAndSwapInt()(CAS) ↓ 如果CAS失败→LockSupport.park() ↓ sun.misc.Unsafe.park() ↓ pthread_cond_wait / futex(Linux) ↓ sys_futex系统调用

三、关键差异分析

1.锁获取策略不同

synchronized(默认非公平):

// JVM的ObjectMonitor::enter代码逻辑(伪代码)voidObjectMonitor::enter(Thread*self){// 1. 直接尝试CAS获取(非公平)if(CAS(&_owner,NULL,self))return;// 2. 检查重入if(self==_owner){_recursions++;return;}// 3. 自旋尝试(自适应自旋)if(TrySpin(self))return;// 4. 进入重量级锁EnterI(self);// 调用系统futex}

ReentrantLock.NonfairSync:

// AQS的非公平获取逻辑finalvoidlock(){if(compareAndSetState(0,1))// 直接插队尝试setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}protectedfinalbooleantryAcquire(intacquires){returnnonfairTryAcquire(acquires);// 非公平尝试}

ReentrantLock.FairSync(公平锁):

protectedfinalbooleantryAcquire(intacquires){finalThreadcurrent=Thread.currentThread();intc=getState();if(c==0){// 关键区别:先检查队列是否有等待者if(!hasQueuedPredecessors()&&// 检查等待队列compareAndSetState(0,acquires)){setExclusiveOwnerThread(current);returntrue;}}// ... 重入逻辑}

2.阻塞/唤醒机制对比

synchronized的阻塞:

// ObjectMonitor::EnterI 中的阻塞(HotSpot源码) void ObjectMonitor::EnterI(Thread* self) { // 将线程加入_cxq(竞争队列) // ... for (;;) { if (TryLock(self) > 0) break; // 最终调用os::PlatformEvent::park() park(); // 调用pthread_cond_wait或futex } }

ReentrantLock的阻塞:

// LockSupport.park()最终调用publicstaticvoidpark(){UNSAFE.park(false,0L);}// HotSpot中的Unsafe.park实现voidParker::park(bool isAbsolute,jlong time){// 使用pthread_cond_t条件变量pthread_cond_wait(&_cond,&_mutex);}

3.操作系统层面的相同本质

实际上,两者在重量级竞争时都会使用相同的系统调用

// Linux下两者的最终系统调用都是futex// 1. synchronized的阻塞syscall(SYS_futex,uaddr,FUTEX_WAIT,val,timeout,uaddr2,val3);// 2. ReentrantLock的阻塞(通过pthread实现)// pthread_mutex_lock -> futex_wait// pthread_cond_wait -> futex_wait

四、性能差异的真正原因

1.锁升级 vs 直接CAS

// synchronized:可能经过锁升级// 偏向锁 → 轻量级锁 → 重量级锁(开销递增)// ReentrantLock:直接CAS尝试// CAS成功:直接获取(用户态)// CAS失败:可能自旋后进入AQS队列

2.自旋策略不同

// synchronized:自适应自旋// - 根据上次自旋是否成功调整下次自旋时间// - JVM参数:-XX:+UseSpinning -XX:PreBlockSpin// ReentrantLock:可控的自旋// 在进入队列前可能自旋,但策略更保守

3.AQS的队列优化

// AQS的CLH队列变体(虚拟队列)// 每个节点通过前驱节点的状态判断是否该唤醒// 减少不必要的唤醒(对比synchronized的随机唤醒)privatevoidunparkSuccessor(Nodenode){// 从尾向前找最前面的有效节点// 避免"惊群效应"}

五、实际系统调用跟踪

使用strace跟踪两种锁的系统调用:

# synchronized的典型调用futex(0x7f8b380008c8, FUTEX_WAIT_PRIVATE,1, NULL)=0futex(0x7f8b380008c8, FUTEX_WAKE_PRIVATE,1)=1# ReentrantLock的典型调用futex(0x7f8b38000900, FUTEX_WAIT_BITSET_PRIVATE,2, NULL, ffffffff)=0futex(0x7f8b38000900, FUTEX_WAKE_BITSET_PRIVATE,1, NULL, ffffffff)=1

六、选择建议

使用synchronized的情况:

  1. 简单的同步场景
  2. 锁竞争不激烈
  3. 需要JVM内置优化(锁升级)
  4. 代码简洁性优先

使用ReentrantLock的情况:

  1. 需要公平锁
  2. 需要tryLock()、lockInterruptibly()等高级功能
  3. 竞争激烈且临界区执行时间长
  4. 需要条件变量(Condition)的精细控制

七、总结

维度synchronizedReentrantLock
OS层面相同(最终都是futex)相同(最终都是futex)
用户态优化锁升级(偏向/轻量级/重量级)AQS队列+CAS自旋
公平性非公平(实现决定)可选择
功能基础丰富(可中断、超时、条件等)
性能低竞争时更优高竞争时可能更优

核心结论

  1. 两者的操作系统底层机制本质相同,都是基于互斥锁和条件变量
  2. 性能差异主要来自用户态的实现策略(锁升级 vs AQS)
  3. synchronized更适合简单场景,依赖JVM优化
  4. ReentrantLock提供更多控制和可预测性

这解释了为什么在低竞争时synchronized可能更快(得益于锁升级),而在高竞争时ReentrantLock可能表现更好(更灵活的CAS和队列管理)。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/29 17:46:02

中文TTS黑科技!使用GLM-TTS实现音素级发音控制与情感迁移

中文TTS黑科技!使用GLM-TTS实现音素级发音控制与情感迁移 在虚拟主播越来越“会演”,有声书配音动辄上百小时的今天,如何让AI合成的声音不仅“听得清”,还能“读得准”“说得动情”?中文语音合成(TTS&#…

作者头像 李华
网站建设 2026/4/17 23:37:55

VHDL课程设计大作业中的FSK调制实现详解

从理论到实践:用VHDL在FPGA上实现FSK调制的完整路径你有没有遇到过这样的情况?手握通信原理课本,看着FSK(频移键控)那一章讲得头头是道——“0”对应一个频率,“1”对应另一个频率,解调还能用包…

作者头像 李华
网站建设 2026/4/28 22:35:10

语音合成中的数字读法控制:金额、日期、电话号码特殊处理

语音合成中的数字读法控制:金额、日期、电话号码特殊处理 在银行App推送一条“您尾号8888的账户入账50,000.00”的通知时,如果语音播报将金额读成“一零五零零零元”,用户不仅会困惑——这到底是五万元还是十万元?更严重的是&…

作者头像 李华
网站建设 2026/5/1 5:06:20

fastbootd与bootloader关系:Qualcomm架构下通俗解释

fastbootd 与 Bootloader 到底什么关系?一文讲透高通平台刷机机制你有没有遇到过这样的情况:在终端敲下fastboot flash system system.img,结果设备报错“Partition not found”?或者明明进了“Fastboot模式”,却无法执…

作者头像 李华
网站建设 2026/4/20 2:17:19

Screen to Gif与Windows相机应用对比分析

从“拍屏幕”到“讲清楚”:Screen to Gif 如何重塑动态内容创作 你有没有过这样的经历?想给同事解释一个操作流程,发了一堆截图还说不明白;写技术文档时,明明几秒钟的动画就能讲清的问题,却要写满一页文字…

作者头像 李华