面试官问:synchronized和ReentrantLock有什么区别?一张图+自动挡比喻,彻底拿下这道必考题(附图解+比喻+避坑指南)

发布时间:2026/7/21 8:30:47
面试官问:synchronized和ReentrantLock有什么区别?一张图+自动挡比喻,彻底拿下这道必考题(附图解+比喻+避坑指南) 面试官问synchronized和ReentrantLock有什么区别一张图自动挡比喻彻底拿下这道必考题附图解比喻避坑指南预计阅读14分钟 你是不是也这样能说出“synchronized是关键字ReentrantLock是类”但面试官一追问“底层原理有什么不同”“公平锁和非公平锁分别适合什么场景”就答不上来了今天一张图 一个自动挡故事 核心对比表 六道追问彻底拿下这道题。摘要synchronized和ReentrantLock都是Java中实现线程同步的可重入锁。synchronized是JVM内置关键字自动加锁释放ReentrantLock是API层面的类需手动加锁解锁。synchronized仅支持非公平锁ReentrantLock支持公平/非公平模式支持中断响应、超时获取、多条件变量。性能方面JDK 1.6后两者差距缩小低竞争时synchronized更优高竞争时ReentrantLock更灵活。一句话简单场景用synchronized复杂需求用ReentrantLock。我是折哥《Java 85题图解版》系列连载中已更新35题建议收藏本系列。每周2-3篇85题通关路线一键追完。点击关注第一时间收到每篇新题推送。上一篇面试官问线程生命周期与状态转换是什么下一篇预告面试官问volatile和Atomic类的底层原理全部85题点击查看总目录关注专栏追更不迷路一句话总结synchronized是“自动挡”ReentrantLock是“手动挡”。底层实现synchronized是JVM关键字基于Monitor监视器 → 像自动挡汽车变速箱自动换挡你只管踩油门和刹车ReentrantLock是JDK API类基于AQS → 像手动挡汽车得自己踩离合换挡还得在finally中松离合unlock。使用方式synchronized自动加锁释放 → 像自动挡只管开ReentrantLock手动lock()/unlock() → 像手动挡得自己控制换挡时机忘记松离合unlock车就趴窝。功能特性synchronized仅非公平锁 → 像只有D挡ReentrantLock支持公平/非公平、中断响应、超时获取 → 像手动挡有多种驾驶模式可以弹射起步、降档超车。背诵口诀简单同步用synchronized复杂需求ReentrantLocksynchronized自动挡ReentrantLock手动挡。核心设计理念synchronized追求简单易用ReentrantLock追求灵活强大。 面试还原面试官synchronized和ReentrantLock有什么区别你平时怎么选这是Java并发面试中必问必考的核心题直接进入正题。 一图看懂synchronized vs ReentrantLock全貌 生活比喻自动挡 vs 手动挡场景设定你开车上路多线程环境需要控制车速线程同步。synchronized 自动挡汽车你只需要踩油门加锁和刹车变速箱JVM自动帮你换挡自动加锁释放不用操心离合器。特点操作简单只管开车不用管换挡自动停车代码结束自动挂P挡释放锁适合大多数人日常通勤简单同步足够用ReentrantLock 手动挡汽车你可以手动控制换挡lock()必须自己踩离合器unlock()。特点操作复杂得会油离配合记得在finally中unlock灵活可以弹射起步公平锁、降档超车tryLock高手专用需要高级驾驶技巧的场景一句话对照synchronized 自动挡简单省心ReentrantLock 手动挡灵活强大。 核心对比表面试速查版维度synchronizedReentrantLock本质JVM关键字JDK API类java.util.concurrent.locks实现Monitor监视器AQSAbstractQueuedSynchronizer加锁方式自动进入同步块时加锁手动lock()释放锁自动离开同步块或异常时释放手动unlock()必须在finally中使用范围方法、代码块仅代码块锁类型仅非公平锁公平锁 / 非公平锁中断响应❌ 不支持✅lockInterruptibly()超时获取❌ 不支持✅tryLock(timeout)尝试获取❌ 不支持✅tryLock()立即返回条件变量1个wait/notify多个Condition性能低竞争⚡ 更优良好性能高竞争良好更稳定、吞吐量更高使用难度简单中等需手动管理锁相同点维度说明可重入性✅ 两者都是可重入锁同步语义✅ 都实现了多线程同步和内存可见性 底层原理深度解析synchronized原理锁升级面试高频⭐synchronized是JVM内置锁JDK 1.6之前是重量级锁。JDK 1.6之后进行了锁升级优化经历四个阶段无锁 → 偏向锁 → 轻量级锁 → 重量级锁偏向锁第一个获取锁的线程只在对象头做标记不真正加锁。如果只有这一个线程全程无加锁开销。轻量级锁出现竞争时升级通过CAS自旋尝试获取锁重量级锁竞争激烈时升级未获取锁的线程阻塞ReentrantLock原理基于AQSReentrantLock基于AQSAbstractQueuedSynchronizer实现。同步状态statevolatile int state0表示未锁定0表示已锁定CLH队列双向链表存放等待锁的线程独占模式ReentrantLock使用AQS的独占模式公平锁 vs 非公平锁公平锁线程严格按照等待顺序获取锁避免饥饿但性能稍低非公平锁新线程先尝试插队获取锁失败再排队吞吐量更高可重入性实现同一个线程多次获取同一把锁时检查当前线程是否是持有锁的线程是则将state加1释放时state减1直到0才真正释放锁 高频面试追问6道大厂真题追问1为什么说synchronized是“自动挡”ReentrantLock是“手动挡”回答要点核心在于锁的获取和释放方式。详细回答synchronized进入同步块时JVM自动加锁离开同步块或抛出异常时JVM自动释放锁开发者无需任何手动操作ReentrantLock需要手动调用lock()加锁且必须在finally块中调用unlock()释放锁。如果忘记释放锁可能导致其他线程永久阻塞追问2公平锁一定比非公平锁好吗回答要点不一定。公平锁避免饥饿但性能更低。详细回答公平锁严格按照线程等待顺序获取锁避免了线程饥饿问题。但也带来了更高的上下文切换开销降低了系统吞吐量。非公平锁允许新线程插队插队提高吞吐量的前提是锁竞争不激烈因为此时插队成功率高且避免了线程挂起减少了上下文切换性能更高。大多数场景下非公平锁的吞吐量更高只有在需要避免饥饿时才使用公平锁。追问3synchronized和ReentrantLock的性能哪个好回答要点JDK 1.6后差距缩小不同场景各有优劣。详细回答JDK 1.5时代ReentrantLock性能显著优于synchronizedJDK 1.6JVM对synchronized进行了大量优化锁升级、自适应自旋等两者性能差距大幅缩小低竞争场景synchronized因JVM内置优化偏向锁等性能可能更优高竞争场景ReentrantLock的灵活性带来更稳定的吞吐量追问4什么是中断响应为什么ReentrantLock支持而synchronized不支持回答要点死锁时synchronized会无限等待ReentrantLock可中断退出。详细回答synchronized获取锁失败会一直阻塞等待无法响应中断。如果发生死锁线程会永远等待下去。ReentrantLock的lockInterruptibly()方法可以在等待锁的过程中响应中断被中断时抛出InterruptedException线程可以捕获异常并做相应处理如释放已持有的资源、记录日志、优雅退出等从而打破死锁。追问5tryLock()有什么用什么时候用回答要点非阻塞尝试获取锁获取失败立即返回用于限时等待场景。详细回答tryLock()尝试获取锁成功返回true失败立即返回false不会阻塞线程。tryLock(timeout)可以指定超时时间。适用场景需要限时等待锁的场景不想让线程无限阻塞获取锁失败时可以执行其他逻辑追问6Condition是什么和wait/notify有什么区别回答要点Condition支持多个等待队列更加灵活精细。详细回答Condition是ReentrantLock的条件变量替代了Object的wait()/notify()方法。维度Object wait/notifyCondition等待队列数量1个多个唤醒方式notify/notifyAll随机唤醒signal/signalAll可指定Condition灵活性较低高可实现精准唤醒使用示例LocklocknewReentrantLock();ConditionnotFulllock.newCondition();ConditionnotEmptylock.newCondition(); 避坑指南序号错误做法正确做法后果1ReentrantLock忘记在finally中unlock始终在finally中unlock锁无法释放线程永久阻塞2在循环中使用synchronized锁粒度太大只锁必要的临界区代码性能下降并发度降低3认为公平锁一定更好根据场景选择默认用非公平锁吞吐量降低4用synchronized处理复杂并发场景改用ReentrantLock或JUC工具类代码复杂且难以维护5把ReentrantLock当synchronized用不响应中断使用lockInterruptibly()处理中断死锁无法打破 可运行验证代码importjava.util.concurrent.locks.ReentrantLock;publicclassLockComparisonDemo{// synchronized示例自动加锁释放 privateintcount10;publicsynchronizedvoidincrementSync(){count1;// JVM自动加锁/释放}// ReentrantLock示例手动加锁释放 privatefinalReentrantLocklocknewReentrantLock();privateintcount20;publicvoidincrementLock(){lock.lock();// 手动加锁try{count2;}finally{lock.unlock();// 必须在finally中释放}}// 公平锁 vs 非公平锁 privatefinalReentrantLockfairLocknewReentrantLock(true);// 公平锁privatefinalReentrantLockunfairLocknewReentrantLock(false);// 非公平锁默认// 可中断锁 publicvoidinterruptibleLock()throwsInterruptedException{lock.lockInterruptibly();// 可响应中断try{// 业务逻辑}finally{lock.unlock();}}// 尝试获取锁 publicbooleantryLockExample(){if(lock.tryLock()){// 非阻塞尝试获取try{// 业务逻辑returntrue;}finally{lock.unlock();}}returnfalse;// 获取失败处理其他逻辑}}❓ 评论区挑战问题以下关于synchronized和ReentrantLock的说法哪一个是错误的classTest{privatefinalReentrantLocklocknewReentrantLock();publicvoidmethod(){lock.lock();// 业务逻辑// 忘记调用 unlock()}}A. synchronized是JVM内置关键字ReentrantLock是JDK API类B. ReentrantLock支持公平锁和非公平锁synchronized只支持非公平锁C. ReentrantLock不需要手动释放锁JVM会自动管理D. ReentrantLock支持中断响应和超时获取锁 欢迎在评论区写出你的答案和理由我会在下一篇文章发布后更新本文公布答案及错误选项逐项解析。✅ 答案公布正确答案C. ReentrantLock不需要手动释放锁JVM会自动管理解析ReentrantLock必须手动释放锁调用unlock()方法忘记释放锁可能导致其他线程永久阻塞正确做法是在finally块中释放锁选项A正确synchronized是关键字ReentrantLock是类选项B正确ReentrantLock可配置公平/非公平选项D正确ReentrantLock支持中断和超时 总结维度synchronizedReentrantLock本质JVM关键字API类实现Monitor监视器AQS加锁释放自动手动finally锁类型仅非公平公平/非公平中断响应❌✅超时获取❌✅条件变量1个多个选型建议简单同步复杂场景面试官最看重的三个点本质区别synchronized是JVM关键字ReentrantLock是API类锁管理方式synchronized自动ReentrantLock手动高级功能ReentrantLock支持公平锁、中断、超时、多Condition 系列导航上一篇面试官问线程生命周期与状态转换是什么下一篇预告面试官问volatile和Atomic类的底层原理全部85题目录点击查看关注专栏每周2-3篇一键追更搭配学习效果更佳本篇图解帮你快速建立知识画面记忆如果想深入理解源码实现和实战避坑细节可以配合姊妹系列《Java 100天进阶之路》对应章节一起学从零基础到上岗就业108篇完整学习地图每篇标配生活类比 可运行代码 避坑表 面试高频题 练习题不背八股文真正讲透“为什么”。 《Java 100天进阶之路》完整目录导航学习建议图解系列负责“快速建立知识图谱”进阶系列负责“深入理解原理”两个系列搭配使用面试备考效率翻倍。你在实际开发中用过ReentrantLock吗有没有遇到过忘记在finally中unlock导致的Bug欢迎评论区分享你的故事