公平锁和非公平锁 源码

ReentrantLock 提供了公平锁和非公平锁,只需要在构造方法中使用一个 boolean 参数即可。默认非公平锁。

公平锁和非公平锁 源码_第1张图片

ReentrantLock 类主要结构


公平锁和非公平锁 源码_第2张图片

ReentrantLock 内部有一个抽象类 Sync,继承了 AQS,同时Sync有两个实现类。这两个实现类就是公平锁 FairSync,是非公平锁NonFairSync。两把锁的主要区别在于lock 方法的实现。

AQS是基于模板模式的实现,不过它的模板模式写法有点特别,整个类中没有任何一个abstract的抽象方法,取而代之的是,需要子类去实现的那些方法通过一个方法体抛UnsupportedOperationException异常来让子类知道。


公平锁和非公平锁 源码_第3张图片

公平锁 FairSync

公平锁和非公平锁 源码_第4张图片

调用的是 AQS 的acquire方法,AQS 会回调子类的 tryAcquire 方法(模版模式,但是不是用的抽象方法),看看公平锁的tryAcquire实现。

公平锁和非公平锁 源码_第5张图片

主要逻辑:

  • 1、获取 state 变量,如果是 0,说明锁可以获取。
  • 2、判断 AQS 队列中是否有等待的线程,如果没有,就使用 CAS 尝试获取。获取成功后,将 CLH 的持有线程修改为当前线程。
  • 3、重入锁逻辑。
  • 4、如果失败,返回 false, AQS 会将这个线程放进队列,并挂起。

重点在判断 AQS 队列中是否有等待的线程,如果有,那么就相当于失败,放入队列并挂起。

非公平锁NonFairSync

公平锁和非公平锁 源码_第6张图片

不需要判断 AQS 队列中是否有等待的线程,直接去发起获取锁操作。如果获取失败,同样是通过模版模式,调取实现类的方法。



公平锁和非公平锁 源码_第7张图片

两个方法不同之处就在于是否判断aqs队列中是否有等待线程。抢不到再进入队列。等待他的前置节点唤醒他。这个过程是公平的。也就是进入队列了,行为就一样了。。

你可能感兴趣的:(公平锁和非公平锁 源码)