ReentrantLock

 三个内部类

当指定公平锁参数时:

 

 

所有的方法都委托给sync:

 AQS(AbstractQueuedSynchronizer):

 

 一个抽象类:

 

维护了一个FIFO队列:

队列的节点结构如下:

 

 

 

 

 

构造方法:

 

父类维护了一个Thread对象,表示当前占用该锁的线程,并且提供了相应的get,set方法:

 简单了解之后,开始“锁”:

 

 

 

cas(compareAndSetState),java.util.concurrent.locks.AbstractQueuedSynchronizer#compareAndSetState:

“native”.java 永远滴神!

cas成功之后便把当前线程设为锁的持有者:

 

失败的话:

 

当tryAcquire不成功并且acquireQueued之后,进行一次interrupt。

首先获取当前锁被重入的次数,如果是0的话,尝试用cas获取一次锁。否则持有锁的线程是否是当前线程,如果是的话增加锁重入的次数。

 

用当前线程实例化一个新的Node节点,如果cas成功追加到Node队列。否则:

死循环重试?完了之后: 

 

如果节点的前一个节点是尝试获取一次锁。

如果不是或者失败了

 

如果已经是signal则代表已经阻塞,如果>0(CANCELLED)往前找第一个<=0的作为node的prev,返回false。如果是0或者-3,会先cas更新waitStatus到SIGNAL但并不会马上阻塞,返回false。

返回之后,if会因为shouldParkAfterFailedAcquire返回false 重新进入一次循环进行一次重试,再次进入shouldParkAfterFailedAcquire时就会出发第一个条件因为SIGNAL返回应该被阻塞。

 

 

 

 

最后如果park成功的话:

cancelAcquire:

 

设置当前node的waitStatus为cancelled 如果当前node在队尾则移除。否则如果前一个节点不是头节点,并且前一个节点是signal或者<=0的情况下cas signal成功,更新前一个节点的下一个节点为当前节点的下一个节点。

如果当前是第二个节点(prev是头节点)或者prev没能成功cas到signal。

 

唤醒当前节点下一个非cannelled的节点

 

看下release:

公平锁和非公平锁的tryRelease是一样的。

 

可重入数的改变。

接着就回到unparkSucceesor;

找到第一个signal的节点unpark

写的更好的:https://www.cnblogs.com/aspirant/p/8657681.html

 

posted @ 2020-07-13 19:26  l2c  阅读(17)  评论(0编辑  收藏