synchronized和reentrantlock的区别

在 Java 中,synchronized 和 ReentrantLock 都用于实现线程同步,但它们在设计理念、功能和使用方式上有显著区别。以下是两者的详细对比:


1. 锁的获取与释放机制

特性 synchronized ReentrantLock
锁的获取 隐式获取:进入同步代码块或方法时自动加锁。 显式获取:需手动调用 lock() 方法。
锁的释放 隐式释放:退出代码块或方法时自动释放(含异常退出)。 显式释放:需在 finally 块中调用 unlock() 方法。
代码示例 synchronized(obj) { ... } lock.lock(); try { ... } finally { lock.unlock(); }

2. 可中断性

特性 synchronized ReentrantLock
中断等待 ❌ 不可中断:线程若未获得锁,会一直阻塞。 ✔️ 可中断:通过 lockInterruptibly() 方法响应中断。
应用场景 不适用于需要中断等待锁的场景。 适合需要超时或中断的同步需求(如死锁恢复)。

3. 公平性

特性 synchronized ReentrantLock
公平锁 ❌ 仅支持非公平锁(默认抢占式)。 ✔️ 支持公平锁(构造函数传 true)。
公平性影响 可能导致线程饥饿。 按请求顺序分配锁,减少饥饿但降低吞吐量。

4. 条件变量(Condition)

特性 synchronized ReentrantLock
条件等待 单一条件:通过 wait()notify()notifyAll() 多条件:通过 newCondition() 创建多个 Condition 对象。
灵活性 仅支持一个等待队列。 可为不同条件创建独立队列(如生产者-消费者模型)。

5. 功能扩展性

特性 synchronized ReentrantLock
尝试获取锁 ❌ 不支持。 ✔️ 支持 tryLock():尝试获取锁,失败立即返回或等待。
超时获取锁 ❌ 不支持。 ✔️ 支持 tryLock(long timeout, TimeUnit unit)
锁状态查询 ❌ 无法查询锁是否被持有。 ✔️ 支持 isLocked()getQueueLength() 等方法。

6. 性能对比

特性 synchronized ReentrantLock
低竞争场景 性能接近,优化后(如偏向锁)甚至更优。 略低,因涉及 API 调用和对象创建。
高竞争场景 可能因锁升级(轻量级锁→重量级锁)导致性能下降。 性能稳定,支持更细粒度的控制。

7. 其他区别

特性 synchronized ReentrantLock
锁的实现 JVM 内置实现(基于 Monitor 机制)。 JDK 层实现(基于 AQS 队列)。
锁的可重入性 ✔️ 支持可重入。 ✔️ 支持可重入。
代码简洁性 简洁,无需手动释放。 需显式管理锁,代码稍繁琐。

8. 使用场景推荐

场景 推荐选择 理由
简单同步 synchronized 代码简洁,无需复杂功能。
需要中断/超时 ReentrantLock 支持 tryLock() 和中断机制。
公平性要求 ReentrantLock(公平模式) 可避免线程饥饿。
多条件变量 ReentrantLock 灵活管理不同等待队列。

总结

  • synchronized:适合简单同步场景,代码简洁,由 JVM 自动管理锁,但功能有限。

  • ReentrantLock:提供更灵活的锁控制(如可中断、公平锁、多条件变量),适合复杂同步需求,但需手动管理锁的获取与释放。

根据具体需求选择:优先考虑 synchronized 以保持代码简洁,仅在需要高级功能时使用 ReentrantLock

你可能感兴趣的:(Java,多线程,锁)