synchronized 和 ReentrantLock 有什么区别?Java 并发加锁应该怎么选?
下面是一段教学用的模拟面试。
🧑💻 面试官:synchronized 和 ReentrantLock 怎么选?
🙋♂️ 我:ReentrantLock 功能更多,所以复杂项目用它。
🧑💻 面试官:只有一个很短的共享计数更新,也需要换吗?
🙋♂️ 我:这种情况 synchronized 更直接。
🧑💻 面试官:如果请求等锁超过一秒就要返回?等待时用户取消请求,又怎么处理?
不是看哪把锁“更高级”,而是看「等待有没有期限、能不能取消、需要怎样通知」。
面试速答(60 秒版)
synchronized 和 ReentrantLock 都可以实现可重入的互斥访问,并提供相应的内存可见性保证。一个线程已经持有这把锁,还能再次进入受同一把锁保护的代码。
synchronized 使用语言层面的同步块或方法,退出相应范围时会释放监视器,写法比较直接。
ReentrantLock 需要显式获取与释放,但提供 tryLock、限时获取、可中断等待和多个 Condition 等能力,也可以选择公平策略。它更适合需要控制等待过程的场景。
如果只是普通的互斥访问,优先选择更容易写对的方式。需要超时、取消或多个等待条件,再考虑 ReentrantLock。不能简单说它一定更快,也不能把公平理解成严格的业务请求顺序。

知识点详解:先把一次等锁过程讲完整
可重入解决的是什么?
假设 update 方法持有一把锁,然后调用 check 方法。check 也需要同一把锁。
如果锁不可重入,同一个线程可能被自己的锁挡住。可重入允许当前持有者再次获取,释放时也要与进入次数对应。
因此,两者的差别不是“一把能重入,另一把不能”。同时,可重入也不会替你解决两把锁之间的死锁。
真正需要比较的是获取、等待和释放
synchronized 进入同步块时获取相应对象的监视器。如果其他线程持有,当前线程等待。正常返回或异常退出同步范围,监视器都会释放。
ReentrantLock 的 lock 获取成功以后,开发者必须保证 unlock 被调用。通常把受保护代码放进 try,再在 finally 释放。只在正常业务结束时释放,异常分支就可能把其他线程一直挡住。
这里说的是 API 使用方式,不是把一整套 Java 锁实现机械翻成 Python Lock 或 JS Promise。它们没有完全相同的行为,本篇不提供伪对应版本。
为什么超时和取消会改变选型?
假设一个查询请求最多允许等待一秒。如果一直拿不到锁,继续排队已经没有意义。
ReentrantLock 可以使用带时间参数的 tryLock,没拿到锁就进入明确的失败处理。使用 lockInterruptibly,则可以让等锁过程响应线程中断。
这两件事也要区分:等待超时不是用户取消;线程中断也不会让所有代码自动退出。应用必须安排如何传递取消信号,以及中断后返回什么。
synchronized 的监视器获取不提供同样的限时和可中断获取接口。需要这类能力时,ReentrantLock 的价值才具体。

一个条件队列,和多个条件队列
假设有一个有限容量的缓冲区。生产者等“有空位”,消费者等“有数据”。
synchronized 可以配合 wait 和 notify/notifyAll;同一个监视器上的等待者共享相应等待机制。ReentrantLock 可以创建多个 Condition,把“非满”和“非空”分开组织。
不过,收到通知不等于条件永远满足。线程重新拿到锁以后,条件可能再次变化,所以应在循环中检查条件,而不是醒来就直接操作。

公平锁为什么不等于订单按顺序成交?
公平策略倾向于照顾等待较久的线程,但线程调度、业务处理和后续 I/O 仍会影响最终完成顺序。未带超时的 tryLock 也有自身的公平策略边界。
它提供的是获取锁的策略,不是从入口到成交的完整排序保证。ReentrantLock 官方文档也明确说明公平性与线程调度的区别。
公平可能牺牲吞吐;非公平也不意味着一定不可用。实际要看等待时间分布和饥饿风险。
面试官继续追问
两者都能保证可见性,是不是锁只需要加在写操作上?
不一定。读写同一份共享可变状态,需要遵守一致的同步约定。写线程加锁,读线程随意读取,不会自动得到你想要的保证。
用 ReentrantLock 就能避免死锁吗?
不能。相反,忘记释放还会新增错误。多锁场景应考虑统一加锁顺序、缩短持锁时间,必要时使用限时获取并正确回退。
怎么比较性能?
使用接近真实的临界区长度、线程数和冲突比例,观察吞吐、等待分布与取消表现。空循环里的结论不能直接搬到包含数据库调用的业务代码。
面试速记卡
- 共同能力:可重入互斥与相应的内存可见性。
- synchronized:同步范围退出时释放,普通互斥容易表达。
- ReentrantLock:显式释放,适合限时、可中断和多条件等待。
- 公平:获取策略,不是全链路的业务顺序保证。
- 选型:先确定等待与取消需求,再谈性能。
公司面试真题
真题根据求职者公开面经整理,题意经过概括,非逐字原话或公司官方题库;本文为 Sunday 的独立解析。
腾讯 · 后台开发 · 原帖未明确批次
synchronized 与 Lock 有哪些区别?(题意整理)
腾讯后台开发面经(HR 部门) ↗
原帖编辑于 2025-02-19美团 · 开发(含 AI 项目追问) · 原帖未明确批次
synchronized 与 Lock 有哪些区别?(题意整理)
美团面经 ↗
原帖发布于 2025-09-09京东 · Java后台 · 校招
synchronized 与 Lock 有什么区别?(题意整理)
京东 Java 后台三面凉经 ↗
原帖编辑于 2019-08-23(历史校招面经)