ReentrantLock 跟 Synchronized 区别
面试回答:
相同点:
-
synchronized 和 ReentrantLock 都是用来保护资源线程安全的。
-
都可以保证可见性。
-
synchronized 和 ReentrantLock 都拥有可重入的特点。
从基本语义和概念上说
-
synchronized
: Java 内建的同步机制 提供互斥性和可见性。 当一个线程获取锁后、其他线程只能等待或阻
synchronized
依赖 JVM 实现、使用更简单、由 JVM 负责锁的获取和释放。
-
ReentrantLock
: Java 5 提供的锁实现。 通过lock()
方法显式获取锁,unlock()
方法显式释放锁。
但需要手动释放锁、否则可能导致死锁。一般会把unlock
操作放入finally
块来解锁、以防忘记解锁。
从锁的公平性来说:
-
ReentrantLock
允许创建公平锁 与非公平锁 -
synchronized
始终是非公平锁。当锁被释放时、哪个等待线程能获取锁是不确定的、可能导致某些线程长时间等待(饥饿)。
从灵活性来说:也就是可中断获取锁
-
synchronized
锁不够灵活:synchronized
一个线程获取锁之后、其他线程想要获取锁只能等待、只能进入阻塞状态、直到持有锁的线程释放这个锁、可能这个等待过程会持续很久。 -
相比之下、ReentrantLock可以使用
lockInterruptibly
方法、不想等了可以中断退出、避免无限期等待-
也可以尝试非阻塞获取锁 (超时获取):提供了尝试非阻塞获取锁的方法 (
tryLock
()),可以立即返回是否成功获取锁。这使得线程可以根据情况决定是否继续等待
-
从实现条件变量 (Condition)来说
-
ReentrantLock
提供了Condition
接口,可以将wait()
、notify()
、notifyAll()
等操作转化为对象行为。 -
Condition
允许线程在特定条件满足时挂起、并在条件满足时被唤醒。 -
ReentrantLock
典型的应用场景是阻塞队列 (如ArrayBlockingQueue
)、用于实现生产者-消费者模式。
从性能来说:(面试可以不回答 感觉没必要)
-
早期版本的
synchronized
性能较差。 -
Java 6 之后,
synchronized
进行了大量优化 (如锁膨胀、偏向锁、轻量级锁等)在低竞争情况下性能可能优于ReentrantLock
。 -
在高竞争情况下,
ReentrantLock
仍然可能具有一定优势
选择建议
-
synchronized: 优先考虑、尤其是在简单同步场景下、代码更简洁、且由 JVM 管理锁的释放、更安全。
-
ReentrantLock: 当需要公平锁、可中断锁、超时锁,或者需要使用多个条件变量时、选择 ReentrantLock。