ReentrantLock 和 synchronized 的锁粒度差异在于锁作用范围的可控性与绑定方式不同:synchronized 锁绑定语法结构,作用域固定且不可跨方法;ReentrantLock 以显式对象为单位,支持跨方法、跨代码段的灵活加解锁及细粒度资源隔离。

ReentrantLock 和 synchronized 在锁粒度上的核心差异,不在于“粗”或“细”的绝对大小,而在于**锁作用范围的可控性与绑定方式不同**。
锁的作用范围可否跨方法?
synchronized 的锁粒度由语法结构决定,天然绑定在代码块或方法上:
- 修饰实例方法 → 锁是当前对象(this),整个方法体为临界区
- 修饰静态方法 → 锁是当前类的 Class 对象,所有该类的静态同步方法共享同一把锁
- 修饰代码块 → 锁对象由开发者显式指定(如 new Object() 或 this),但仅对该代码块生效
也就是说,synchronized 的锁作用域无法脱离其声明位置——它不能在 methodA 中加锁、在 methodB 中解锁,也不支持将一次加锁延续到多个分散的逻辑段中。
ReentrantLock 支持更灵活的粒度控制
ReentrantLock 是一个独立对象,锁的状态与其使用位置解耦:
立即学习“Java免费学习笔记(深入)”;
- 可以在 methodA 中调用 lock(),在 methodB 中调用 unlock()(只要保证成对且线程一致)
- 可以复用同一个 lock 实例保护多个不连续的代码段,甚至跨多个类的方法调用链
- 配合 tryLock(timeout) 或 tryLock(),还能实现“按需窄化”临界区——比如只在真正需要写入时才尝试获取锁,避免长时间持有
这种能力让 ReentrantLock 能实现比 synchronized 更精细的资源隔离。例如,在缓存更新逻辑中,可对“检查是否存在”和“加载并写入”两个动作分别加锁或组合加锁,而不是被迫把整段流程包进一个大同步块。
锁对象本身的粒度选择权
synchronized 的锁对象隐含且固定:
- 实例方法 → 锁 this,粒度是整个对象
- 静态方法 → 锁 Class,粒度是整个类
- 代码块 → 虽然可自定义锁对象,但通常要额外创建新对象,容易误用(如每次 new Object() 导致锁失效)
ReentrantLock 则始终以显式创建的 lock 实例为单位,开发者完全掌控其生命周期和复用策略:
- 一个 lock 可保护某字段、某集合、某业务状态,而不必牵连整个对象
- 可为不同资源分配不同 lock,避免“一把锁管全局”的争用放大问题
比如对 HashMap 的读写操作,synchronized 往往只能锁整个 map 对象;而用 ReentrantLock 可设计分段锁(类似 ConcurrentHashMap 思路),或为 key 哈希桶分配独立锁,显著降低竞争。


















