写在前面
作者Doug Lea_如此描述这个类:_A reentrant mutual exclusion {@link **java.util.concurrent.locks.Lock} with the same basic behavior and semantics as the implicit monitor lock accessed using {@code **synchronized} methods and statements, but with extended capabilities.
分析自 JDK 1.8.0_171
ReentrantLock是继承 _java.util.concurrent.locks.Lock _的可重入互斥锁,它具有跟隐式监视器锁(Synchronized)同样语义,用于锁定一个方法或代码块,除此之外,它还有一些额外的功能。
ReentrantLock锁,只能被一个线程持有,如果该线程持有的同时尝试去获取该ReentrantLock,会立即返回。当一个线程获取ReentrantLock,即调用lock时,只有当该锁未被其它线程持有时才能成功。
看一下源码中的示例:
1 | class X { |
另外,还有个lock.newCondition api可以使用,看下面用法:
1 | public class Y { |
ReentrantLock.lock
还是结合示例,看看整个流程是怎么串起来的。
有如下两个构造函数:
1 | public ReentrantLock() { |
构造时通过传入一个boolean参数,可以实例化一个公平Lock。而这里的 FairSync
和 NonfairSync
是继承自内部类Sync,而Sync则继承自AQS。如下代码:
Sync类
1 | abstract static class Sync extends AbstractQueuedSynchronizer { |
内部抽象类 Sync
继承AQS,实现了一些基础功能,内部有个抽象方法lock。子类实现这个方法可提供公平/非公平锁的功能。
NonFairSync类
1 | static final class NonfairSync extends Sync { |
FairSync类
1 | static final class FairSync extends Sync { |
以上代码分析,非公平锁,通过cas操作state去获取锁,即0->1,如果获取失败,则再次尝试(cas操作state,持有者是否为当前线程),如果仍然获取失败,则构造一个node并接入链表尾部,并阻塞当前线程直到被唤醒。公平锁则不会直接去获取锁,而是在非公平锁基础上,会先查看链表是否有前驱,有则阻塞并构造新节点加入链表尾部。
辅助下面的图看源码可能会有帮助。
非公平锁:
公平锁:
ReentrantLock.unlock
释放锁的逻辑相对获取锁要简短很多。unlock方法就是调用AQS的release方法:
1 | public final boolean release(int arg) { |
ReentrantLock.newCondition
接下来看一下newCondition这个api的内部流程是什么样的。ReentrantLock.newCondition
方法内部调用Sync类实现的 newCondition
方法,而这个方法是实例化一个AQS的 ConditionObject
类对象:
1 | final ConditionObject newCondition() { |
await方法的比较复杂,需要仔细梳理下,并且结合signal的流程才能清晰起来。
以下为signal的流程:
1 | public class ConditionObject implements Condition, java.io.Serializable { |
signal流程大致就是这样,signalAll其实就是从Condition头结点firstWaiter开始依次调用transferForSignal方法,大同小异。