使用ReentrantLock替代synchronized是否属于不良编程实践?
问题解答
1. 所有synchronized的适用场景都可以用ReentrantLock替代吗?
几乎所有常规开发场景都可以完全替代,核心依据如下:
- 二者都是可重入锁,同一个线程重复加锁不会产生死锁,基础互斥能力完全对齐
- synchronized支持的对象锁、类锁、代码块锁三种常用用法,都可以通过声明对应作用域的
ReentrantLock实例,配合try-finally块手动实现,运行逻辑完全等价 - 仅有的特殊例外是极个别依赖JVM内置锁机制的边缘场景:比如部分JVM诊断工具会专门采集synchronized锁的持有状态、部分老旧框架依赖内置锁的monitor机制,这类场景下ReentrantLock无法完全对齐,但日常业务开发基本不会遇到。
2. 习惯优先用ReentrantLock属于不良实践吗?
不算原则性的不良实践,但存在明确的潜在弊端:
- 需要手动保证锁的释放:必须把
unlock()操作放在finally块中,一旦漏写或者代码逻辑异常提前跳出,就会出现锁泄露问题,而synchronized由JVM自动释放锁,完全没有这类风险 - 代码冗余度更高:原本synchronized只要一行代码包裹逻辑块,用ReentrantLock需要多写加锁、finally释放的模板代码
- 无额外收益:JDK1.6之后JVM对synchronized做了大量优化(偏向锁、轻量级锁、锁粗化、锁消除等),普通无特殊需求的场景下二者性能几乎没有差异,你不会因为换用ReentrantLock得到额外好处。
3. 是否应当优先使用synchronized?
绝大多数场景下推荐优先用synchronized,只有当你需要ReentrantLock独有的能力时再切换:
- 需要使用可中断的锁等待:
lockInterruptibly()方法允许等待锁的过程中响应中断,synchronized不支持该能力 - 需要非阻塞的尝试加锁:
tryLock()可以指定超时时间,拿不到锁就直接返回,不需要一直阻塞等待 - 需要使用公平锁策略:ReentrantLock可以在构造时指定
fair=true实现先来先得的公平锁,synchronized只能使用非公平锁 - 需要绑定多个条件变量:可以通过
newCondition()生成多个Condition实例,实现分组唤醒等待线程,synchronized只能用内置的wait/notify/notifyAll,要么唤醒单个要么唤醒全部,灵活性不足。
补充:如果你只是偏好try-catch-finally的写法,且能100%保证不会漏写finally释放锁的逻辑,那坚持用ReentrantLock也不会产生严重问题,不属于原则性的编码错误。
内容的提问来源于stack exchange,提问作者Spyromancer
相关产品推荐
相关产品推荐

