news 2026/5/19 7:01:02

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/5/13 23:04:24

全面讲解Keil5软件下载与注册激活流程

手把手带你搞定Keil5安装与激活:从零开始的嵌入式开发第一步 你是不是也曾在准备开启STM32开发之旅时,卡在了 Keil5怎么下载?怎么注册?为什么编译到一半报错“code size limited to 32KB”? 这些看似简单却让人抓狂…

作者头像 李华
网站建设 2026/5/19 1:38:03

语音克隆也能做SaaS?结合GPU资源售卖搭建TTS服务平台

语音克隆也能做SaaS?结合GPU资源售卖搭建TTS服务平台 在AIGC内容爆炸的今天,个性化语音正在从“可有可无”的附加功能,演变为数字内容的核心竞争力。无论是虚拟主播的一颦一笑,还是智能客服的语气起伏,用户对“像人一样…

作者头像 李华
网站建设 2026/5/15 17:21:36

【线性表系列进阶篇】手搓单向链表:从指针迷宫到代码实现

🏠个人主页:黎雁 🎬作者简介:C/C/JAVA后端开发学习者 ❄️个人专栏:C语言、数据结构(C语言)、EasyX、游戏、规划、程序人生 ✨ 从来绝巘须孤往,万里同尘即玉京 文章目录【线性表系列…

作者头像 李华
网站建设 2026/5/18 23:26:16

语音合成中的背景音乐叠加方案:GLM-TTS输出混音技巧

语音合成中的背景音乐叠加方案:GLM-TTS输出混音技巧 在短视频、播客、AI主播和在线教育内容爆发式增长的今天,单纯“能说话”的语音合成已经不够用了。用户期待的是更具沉浸感的声音体验——比如一段温柔叙述配上轻柔钢琴,或是一条激情广告搭…

作者头像 李华
网站建设 2026/5/13 6:46:40

GLM-TTS能否离线运行?完全脱离网络的本地语音合成方案

GLM-TTS能否离线运行?完全脱离网络的本地语音合成方案 在智能语音应用日益普及的今天,越来越多用户开始关注一个核心问题:我的声音数据是否真的安全? 尤其是当使用云端TTS服务朗读私密文档、生成个性化音频时,文本和参…

作者头像 李华
网站建设 2026/5/12 14:49:10

星际航线的最小能耗-最短路板子题

题目描述:在茫茫宇宙中分布着n个星际空间站(编号为1到 n)。为了建立联络,空间站之间开通了m条单向的虫洞航线。每条航线从空间站u通向空间站v,通行需要消耗w单位的能量。作为舰队指挥官,你目前位于编号为s的…

作者头像 李华