news 2026/4/28 17:22:19

synchronized 与 JUC 锁对比

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
synchronized 与 JUC 锁对比

一、先说结论

面试时被问到这个问题,直接先甩结论:

特性synchronizedJUC Lock(ReentrantLock)
实现层级JVM 内置(C++)Java + AQS 框架
锁释放自动释放手动释放(必须 finally)
公平锁❌ 不支持✅ 支持
可中断等待❌ 不支持✅ 支持(lockInterruptibly)
多条件队列❌ 单个 wait/notify✅ 多个 Condition
锁尝试获取❌ 不支持✅ 支持(tryLock)
性能(JDK 1.6+)几乎一致高并发略优

记住一句话:synchronized 能用就用,需要高级特性再换 Lock。


二、synchronized 的底层原理

很多人只知道 synchronized 能加锁,但不知道它背后发生了什么。

2.1 锁存在哪?—— Mark Word

Java 对象的内存分为三部分:对象头、实例数据、对齐填充。

synchronized 的锁信息存在对象头的 Mark Word 里。

32 位 JVM 的 Mark Word 结构:

状态Mark Word 内容
无锁hashcode(25位) + age(4位) + biased_lock(1位) + lock(2位)
偏向锁thread(23位) + epoch(2位) + age(4位) + biased_lock(1位) + lock(2位)
轻量级锁指向栈中锁记录的指针(30位)
重量级锁指向 Monitor 的指针(30位)

64 位 JVM 类似,只是位数扩展了。

2.2 锁升级过程

这是面试超高频题,必须搞清楚。

无锁 → 偏向锁 → 轻量级锁 → 重量级锁

阶段一:偏向锁

第一个线程访问同步块时,JVM 把线程 ID 记录到 Mark Word。

Mark Word: [线程ID | 偏向锁标志位 | lock标志位]

下次这个线程再进入,只需要比较线程 ID,零 CAS 开销

阶段二:轻量级锁

第二个线程来了,发现 Mark Word 里的偏向锁不是自己的。

JVM 在当前线程的栈帧里创建一个锁记录(Lock Record),然后 CAS 把 Mark Word 复制到栈帧,同时把 Mark Word 改成指向栈帧的指针。

Mark Word: [指向栈帧Lock Record的指针]

其他线程来了就自旋等着,不阻塞线程,只是空转 CPU。

阶段三:重量级锁

自旋次数超过阈值(默认 10 次),或者自旋线程太多(CPU 核数一半以上),锁膨胀为重量级锁。

重量级锁依赖操作系统的 Mutex 实现,线程进入阻塞状态,不消耗 CPU。

Mark Word: [指向Monitor的指针] Monitor: Owner(持有者) + EntryList(等待队列) + WaitSet(等待notify的队列)

这就是为什么很多人说 synchronized “慢”,因为它早期确实是重量级锁。但 JDK 1.6 之后加了偏向锁和轻量级锁优化,日常场景基本和 ReentrantLock 性能持平。

踩坑一:偏向锁在 JDK 15 后被废弃

如果你用的是 JDK 15+ 的版本,默认已经禁用了偏向锁(-XX:+UseBiasedLocking默认 false)。

线上有同学碰到过,因为这个参数导致 synchronized 性能不符合预期。


三、ReentrantLock 的底层原理

ReentrantLock 是 JUC 里最常用的锁,它的底层靠的是AQS(AbstractQueuedSynchronizer)

3.1 AQS 是什么?

AQS 是 JUC 包里很多组件的基石,不只是锁:

ReentrantLock → AQS Semaphore → AQS CountDownLatch → AQS CyclicBarrier → ReentrantLock ...

AQS 核心结构就两个东西:

  1. state:一个 volatile 的 int,表示锁状态

    • 0:没有被持有

    • 0:被持有,值 = 重入次数

  2. CLH 队列:一个双向链表,存储等待线程

3.2 加锁流程(以非公平锁为例)

// ReentrantLock.NonfairSync.lock()finalvoidlock(){// 1. 直接 CAS 抢锁if(compareAndSetState(0,1))setExclusiveOwnerThread(Thread.currentThread());else// 2. 抢不到,尝试获取锁acquire(1);}// AQS.acquire()publicfinalvoidacquire(intarg){// 3. tryAcquire 由子类实现(ReentrantLock重写)if(!tryAcquire(arg)&&// 4. 获取失败,加入等待队列acquireQueued(addWaiter(Node.EXCLUSIVE),arg))// 5. 如果被中断过,自旋中止selfInterrupt();}

关键点:非公平锁上线就 CAS 抢,不排队。公平锁会先看看队列里有没有人,有的话就老实排队。

3.3 解锁流程

publicvoidunlock(){sync.release(1);}// AQS.release()publicfinalbooleanrelease(intarg){if(tryRelease(arg)){Nodeh=head;if(h!=null&&h.waitStatus!=0)// 唤醒后继节点unparkSuccessor(h);returntrue;}returnfalse;}

ReentrantLock 的可重入:每加一次锁 state +1,每解锁一次 state -1,必须完全释放(state 归 0)才真正解锁。


四、核心区别对比

4.1 功能维度

能力synchronizedReentrantLock
锁获取synchronized void method()lock.lock()
锁释放自动(出方法体)手动lock.unlock()
尝试获取lock.tryLock()
超时获取lock.tryLock(5, TimeUnit.SECONDS)
可中断等待lock.lockInterruptibly()
公平锁new ReentrantLock(true)
多条件控制❌(单 wait 队列)✅(多个 Condition)

4.2 代码写法对比

synchronized 版:

synchronized(this){count++;}// 自动释放,不用管

ReentrantLock 版:

privatefinalReentrantLocklock=newReentrantLock();publicvoidincrement(){lock.lock();try{count++;}finally{lock.unlock();// 必须手动释放,而且要放 finally!}}

这就是为什么 synchronized 更安全——忘了写 finally 块,ReentrantLock 的锁永远不会释放,程序分分钟死锁。

4.3 条件变量的坑

synchronized 的 wait/notify 只能有一个等待队列。

ReentrantLock 的 Condition 可以创建多个独立队列:

ReentrantLocklock=newReentrantLock();ConditionconditionA=lock.newCondition();ConditionconditionB=lock.newCondition();// 线程 A 等待 conditionAconditionA.await();// 线程 B 等待 conditionBconditionB.await();// 唤醒 conditionA 上的所有线程conditionA.signalAll();

典型场景:生产者-消费者,一个队列放生产者,一个队列放消费者,比 synchronized 的 wait/notify 清晰得多。

踩坑二:ReentrantLock 的手动释放陷阱

publicvoidwrong(){lock.lock();if(condition){return;// ❌ 锁永远不释放!}lock.unlock();}publicvoidright(){lock.lock();try{if(condition){return;// ✅ try 块里随便 return}}finally{lock.unlock();// finally 保证释放}}

五、ReadWriteLock:读多写少场景的利器

synchronized 和 ReentrantLock 都是排他锁,同一时刻只能一个线程进入。

如果你的场景是读多写少,排他锁就太浪费了。

privatefinalReadWriteLockrwLock=newReentrantReadWriteLock();privatefinalLockreadLock=rwLock.readLock();privatefinalLockwriteLock=rwLock.writeLock();// 读操作(多个线程可以同时读)publicintget(){readLock.lock();try{returncount;}finally{readLock.unlock();}}// 写操作(独占)publicvoidset(intvalue){writeLock.lock();try{count=value;}finally{writeLock.unlock();}}

原理:读锁是共享锁,写锁是排他锁。读的时候其他线程也能读,写的时候其他线程都不能操作。

踩坑三:ReadWriteLock 的读锁不是绝对并发的

读锁虽然是共享的,但如果有一个线程持有读锁,此时有写锁请求进来,后续的读请求会阻塞——这叫写饥饿

解决方案:用 StampedLock 的乐观读模式。


六、高频面试 Q&A

Q1:synchronized 和 ReentrantLock 的区别?

甩结论 + 逐条解释:

  • synchronized 是 JVM 内置锁,自动释放
  • ReentrantLock 是 JUC 锁,手动释放,需要 finally
  • synchronized 不支持公平锁、公平锁、可中断
  • ReentrantLock 支持 tryLock、公平锁、lockInterruptibly
  • ReentrantLock 有多 Condition,synchronized 只有单个 wait 队列

Q2:synchronized 可以完全替代 ReentrantLock 吗?

不能。以下场景必须用 ReentrantLock:

  1. 需要公平锁(synchronized 不支持)
  2. 需要可中断等待(lockInterruptibly)
  3. 需要 tryLock 尝试获取(不阻塞)
  4. 需要多个等待队列(多 Condition)
  5. 需要 ReadWriteLock/StampedLock 优化读多写少场景

Q3:synchronized 锁升级过程?

无锁 → 偏向锁(单线程)→ 轻量级锁(多线程自旋)→ 重量级锁(OS Mutex)

关键:只能升级不能降级。

Q4:为什么 JDK 1.6 后 synchronized 性能变好了?

因为加入了偏向锁和轻量级锁优化。大部分场景锁只被一个线程持有,偏向锁零开销;多线程交替执行时用轻量级锁自旋,不需要进入内核态。


七、记忆口诀

synchronized:自动、简单、够用 ReentrantLock:手动、复杂、功能全 AQS:state + CLH队列,JUC的基石 读多写少:ReadWriteLock tryLock+lockInterruptibly+多Condition,选ReentrantLock

八、选型总结

场景推荐
简单同步,代码要简洁synchronized
需要公平锁ReentrantLock
需要可中断等待ReentrantLock
需要 tryLock 限时获取ReentrantLock
读多写少,高并发读ReadWriteLock
需要乐观读 + 写锁StampedLock
分布式环境跨 JVMRedis 分布式锁(都不是这两种)

最后一句话:synchronized 能用就用,它经过了 JVM 这么多年优化,简单安全。大多数场景不需要换 Lock,除非你有明确的高级特性需求。

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

2026届必备的降AI率网站实测分析

Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 在当下人工智能内容生成技术处于广泛普及的状况下,各种各样的AI检测系统随之渐渐…

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

终极解决方案:Mac用户如何实现微信聊天记录无损备份与可视化查看

终极解决方案:Mac用户如何实现微信聊天记录无损备份与可视化查看 【免费下载链接】WeChatExporter 一个可以快速导出、查看你的微信聊天记录的工具 项目地址: https://gitcode.com/gh_mirrors/wec/WeChatExporter WeChatExporter为Mac用户提供了一套完整的微…

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

3分钟快速上手:OBS RTSP服务器插件完整使用指南

3分钟快速上手:OBS RTSP服务器插件完整使用指南 【免费下载链接】obs-rtspserver RTSP server plugin for obs-studio 项目地址: https://gitcode.com/gh_mirrors/ob/obs-rtspserver 想要将OBS Studio的专业直播内容无缝推送到监控系统、智能电视或局域网内的…

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

Win11Debloat深度实战:Windows系统去臃肿与隐私保护终极攻略

Win11Debloat深度实战:Windows系统去臃肿与隐私保护终极攻略 【免费下载链接】Win11Debloat A simple, lightweight PowerShell script that allows you to remove pre-installed apps, disable telemetry, as well as perform various other changes to declutter …

作者头像 李华
网站建设 2026/4/28 17:17:28

3步搞定Mac微信聊天记录备份与查看:WeChatExporter完全指南

3步搞定Mac微信聊天记录备份与查看:WeChatExporter完全指南 【免费下载链接】WeChatExporter 一个可以快速导出、查看你的微信聊天记录的工具 项目地址: https://gitcode.com/gh_mirrors/wec/WeChatExporter 你是否曾因为误删重要微信消息而懊恼?…

作者头像 李华