ReentrantLock 提供了公平锁和非公平锁,只需要在构造方法中使用一个 boolean 参数即可。默认非公平锁。
ReentrantLock 类主要结构
ReentrantLock 内部有一个抽象类 Sync,继承了 AQS,同时Sync有两个实现类。这两个实现类就是公平锁 FairSync,是非公平锁NonFairSync。两把锁的主要区别在于lock 方法的实现。
AQS是基于模板模式的实现,不过它的模板模式写法有点特别,整个类中没有任何一个abstract的抽象方法,取而代之的是,需要子类去实现的那些方法通过一个方法体抛UnsupportedOperationException异常来让子类知道。
公平锁 FairSync
调用的是 AQS 的acquire方法,AQS 会回调子类的 tryAcquire 方法(模版模式,但是不是用的抽象方法),看看公平锁的tryAcquire实现。
主要逻辑:
- 1、获取 state 变量,如果是 0,说明锁可以获取。
- 2、判断 AQS 队列中是否有等待的线程,如果没有,就使用 CAS 尝试获取。获取成功后,将 CLH 的持有线程修改为当前线程。
- 3、重入锁逻辑。
- 4、如果失败,返回 false, AQS 会将这个线程放进队列,并挂起。
重点在判断 AQS 队列中是否有等待的线程,如果有,那么就相当于失败,放入队列并挂起。
非公平锁NonFairSync
不需要判断 AQS 队列中是否有等待的线程,直接去发起获取锁操作。如果获取失败,同样是通过模版模式,调取实现类的方法。
两个方法不同之处就在于是否判断aqs队列中是否有等待线程。抢不到再进入队列。等待他的前置节点唤醒他。这个过程是公平的。也就是进入队列了,行为就一样了。。