前言
ReentrantLock是非常常用的锁,在前面【从入门到放弃-Java】并发编程-JUC-LinkedBlockingQueue在我们了解到,LinkedBlockingQueue入队、出队都是依赖ReentrantLock进行锁同步和线程唤醒、等待的。
本文来学习下ReentrantLock。
ReentrantLock
1 | /** |
通过构造函数,我们可以看到可以根据参数fair,生成公平的同步和不公平的同步模式。
接下来需要看下FairSync和NonfairSync到底是何方神圣
Sync

Sync是一个抽象类,FairSync和NonfairSync都继承自Sync并实现了tryAcquire方法,tryAcquire是在AbstractQueuedSynchronizer(AQS)中声明的。
AbstractQueuedSynchronizer中的方法非常多,我们通过ReentrantLock中各方法的调用来逐步熟悉它。
ReentrantLock::lock
1 | public void lock() { |
请求锁,如果加锁失败则一直等待。
ReentrantLock中加锁的方法非常简洁,直接调用sync的acquire方法
下面我们看下acquire的具体实现。
AbstractQueuedSynchronizer::acquire
1 | /** |
- 首先尝试获取锁(具体实现下面分析),获取成功函数结束
- 获取失败,则加入等待队列一直自旋尝试获取锁直到获取成功或超时。
- 如果获取失败,则抛出中断异常
NonfairSync::tryAcquire
1 | /** |
- 如果没锁,则尝试获取锁
- 如果有锁,判断是否是当前线程持有的
- 是当前线程持有,则state值加1 返回加锁成功。即重入锁
- 不是当前线程持有,则加锁失败
FairSync::tryAcquire
1 | /** |
ReentrantLock::lockInterruptibly
1 | public void lockInterruptibly() throws InterruptedException { |
请求锁,如果失败则一直阻塞等待 直到获取锁或线程中断
ReentrantLock::tryLock
1 | public boolean tryLock() { |
请求锁,如果请求失败,则返回false
ReentrantLock::unlock
1 | public void unlock() { |
释放锁,直到state=0完全释放时,线程owner设置为null
ReentrantLock::newCondition
1 | public Condition newCondition() { |
ConditionObject::await
线程释放锁,阻塞挂起,直到被signal唤醒,则继续尝试获取锁
1 | public final void await() throws InterruptedException { |
ConditionObject::awaitNanos
线程释放锁,阻塞挂起一段时间,直到被signal唤醒或超时,则继续尝试获取锁
1 | public final long awaitNanos(long nanosTimeout) |
ConditionObject::awaitUntil
线程释放锁,阻塞挂起一段时间,直到被signal唤醒或到指定时间,则继续尝试获取锁
1 | public final boolean awaitUntil(Date deadline) |
ConditionObject::signal
把首节点的status设置为Node.SIGNAL 则阻塞的线程循环判断发现statue状态变了,则唤醒继续执行。如果设置status失败,则在此线程中调用LockSupport.unpark唤醒阻塞的线程
1 | public final void signal() { |
ConditionObject::signalAll
唤醒所有的节点。
1 | public final void signalAll() { |
总结
在【从入门到放弃-Java】并发编程-锁-synchronized中,我们学习内置锁synchronized,与ReentrantLock对比
- 两者都是可重入的互斥锁。
- synchronized是隐式的加解锁,不需要手动解锁。而ReentrantLock需要显式的lock和unlock。lock加锁多少次,对应的就需要unlock多少次。因此一般都会在finally中unlock。避免因异常等情况导致锁无法释放
- ReentrantLock通过AQS(volatile state + CAS + CLH队列实现)加解锁。synchronized是通过monitor实现(存在偏向锁、轻量级锁、重量级锁等锁升级)。
- ReentrantLock可以使用lockInterruptibly响应中断,synchronized只能傻等、等到死
- ReentrantLock可以使用非公平锁和公平锁模式,可以通过非公平性减少CAS的竞争,提升性能。也可以通过公平锁减少线程饥饿情况发生
- ReentrantLock可以创造多个Condition,来实现线程等待通知机制(阻塞、唤醒)