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