ReenTrantLock源码浅析

ReenTrantLock是什么

ReenTrantLock是juc包下的一个经典的互斥锁,也是 可重入锁(即当前线程在已经获取改锁后重复执行获取锁操作时不会引起死锁,并且不需要执行获取锁的操作),ReenTrantLock是基于AQS来实现的(PS:注意是基于不是继承,看到网上有的同学会说发现ReentrantLock并没有继承AQS有所疑问),如果有对AQS不了解的同学可以查看我之前的文章浅析AQS(1)---独占锁以及共享锁的实现以及浅析AQS (二)--condition的实现,

首先ReenTrantLock是默认的非公平锁,但是也有公平锁的实现,需要在构造方法中传入是否公平的Boolean值来标志,需要注意的是,此处的公平与非公平只针对lock方法,而tryLock方法是指定非公平的.并不受限制

ReenTrantLock实现并发控制是依靠内部类Sync及其两个子类FairSync和NoFairSync,顾名思义这两个子类是提供公平锁以及非公平锁的实现,而Sync则是继承了AQS的具体实现类,接下来我们结合源码具体分析

Sync内部类

首先查看一下Sync的源码

abstractstaticclassSyncextendsAbstractQueuedSynchronizer{

privatestaticfinallong serialVersionUID = -5179523762034025860L;

//抽象lock方法 根据公平与非公平实现执行不同的操作

abstractvoidlock();

//非公平尝试获取锁

finalbooleannonfairTryAcquire(int acquires){

final Thread current = Thread.currentThread();

int c = getState();

if (c == 0) {

//如果当前锁没有被人获取过则直接尝试获取锁

if (compareAndSetState(0, acquires)) {

//设置当前持有锁的线程

setExclusiveOwnerThread(current);

returntrue;

}

}

elseif (current == getExclusiveOwnerThread()) {

//如果是当前线程获取了当前锁则直接重入

int nextc = c + acquires;

if (nextc < 0) // overflow

thrownew Error("Maximum lock count exceeded");

setState(nextc);

returntrue;

}

returnfalse;

}

//尝试释放锁

protectedfinalbooleantryRelease(int releases){

int c = getState() - releases;

if (Thread.currentThread() != getExclusiveOwnerThread())

thrownew IllegalMonitorStateException();

boolean free = false;

if (c == 0) {

free = true;

setExclusiveOwnerThread(null);

}

setState(c);

return free;

}

// 是否持有当前锁

protectedfinalbooleanisHeldExclusively(){

return getExclusiveOwnerThread() == Thread.currentThread();

}

//新建condition对象

final ConditionObject newCondition(){

returnnew ConditionObject();

}

//获取锁当前的持有线程

final Thread getOwner(){

return getState() == 0 ? null : getExclusiveOwnerThread();

}

//当前线程获取到了

finalintgetHoldCount(){

return isHeldExclusively() ? getState() : 0;

}

finalbooleanisLocked(){

return getState() != 0;

}

}

在Sync对象中,重写了tryRelease方法,将释放锁的逻辑统一,并且定义了nonfairTryAcquire非公平获取锁的方法,这里为什么要将该方法定义在父类是因为无论是公平还是非公平锁,tryLock方法中都是采用非公平获取的方式,而无论维护的Sync对象时公平的还是非公平的,我们都需要一个可以非公平获取锁的方式

在nonfairTryAcquire我们可以看到,如果当前锁的state为0即当前锁没人持有时则采用cas的方式获取锁,然后将持有现成设置为当前线程,而第二个判断则是可重入锁的实现,即判断持有锁的是不是当前线程,如果是则直接获取锁

关于ConditionObject的实现可以查看我以前的文章浅析AQS (二)--condition的实现,

FairSync与NoFairSync

下面放一下公平与非公平锁的具体实现

staticfinalclassNonfairSyncextendsSync{

privatestaticfinallong serialVersionUID = 7316153563782823691L;

finalvoidlock(){

//尝试获取锁

if (compareAndSetState(0, 1))

setExclusiveOwnerThread(Thread.currentThread());

else

acquire(1);

}

protectedfinalbooleantryAcquire(int acquires){

return nonfairTryAcquire(acquires);

}

}

staticfinalclassFairSyncextendsSync{

privatestaticfinallong serialVersionUID = -3000897897090466540L;

finalvoidlock(){

acquire(1);

}

protectedfinalbooleantryAcquire(int acquires){

final Thread current = Thread.currentThread();

int c = getState();

if (c == 0) {

//判断是否有在队列中阻塞的线程,或者当前线程是否为队列的头

if (!hasQueuedPredecessors() &&

compareAndSetState(0, acquires)) {

setExclusiveOwnerThread(current);

returntrue;

}

}

elseif (current == getExclusiveOwnerThread()) {

int nextc = c + acquires;

if (nextc < 0)

thrownew Error("Maximum lock count exceeded");

setState(nextc);

returntrue;

}

returnfalse;

}

在NoFairSync中调用lock方法直接尝试用cas的方式获取锁,并不去查看你是否有锁占用,直接尝试获取,如果成功则直接获取锁,如果失败则采用acquire的方式来获取

而在FairSync中实现的tryAcquire方法中与Sync类中的noFairTryAcquire基本一致,只是在没人获取锁时判断当前队列是否为空,或者当前线程是否在队列的最开始位置,总得来说就是判断是否有其他线程等待时长比当前线程要长,主要是为了保证获取锁的公平性

ReenTrantLock

接下来我们看看ReenTrantLock是如何使用这两种锁的,首先来看看构造方法

publicReentrantLock(){

sync = new NonfairSync();

}

publicReentrantLock(boolean fair){

sync = fair ? new FairSync() : new NonfairSync();

}

这里指定了锁的公平与非公平,默认采用非公平锁,如需公平锁则传入一个true即可

接下来查看lock与tryLock方法

publicvoidlock(){

sync.lock();

}

publicbooleantryLock(){

return sync.nonfairTryAcquire(1);

}

如同上文所说,在lock方法中是根据当前所公平与非公平来进行而tryLock方法则是固定以非公平的方式来进行调用

以上就是ReenTrantLock的具体实现方式,结合AQS的两篇文章即可将该类理解通透

我的公众号

以上是 ReenTrantLock源码浅析 的全部内容, 来源链接: utcz.com/a/32944.html

回到顶部