Reentrantlock是并发包中可重入的独占锁,只能有一个线程占有锁,锁的获取和释放是基于AQS(AbstractQueuedSynchronized)实现的, 有公平和不公平两种获取锁的实现方式。Reentranlock 中有一个内部抽象类Sync继承自AbstractQueuedSynchronized, 主要是它来实现锁获取和释放的功能,Sync 在ReentrantLock中有两种实现类:NonfairSync(非公平获取锁)、FairSync(公平获取锁), Reentrantlock支持Condition,AQS中有同步队列和条件队列,不清楚的,能够看下个人另外一篇AbstractQueuedSynchronized的源码分析juejin.im/post/5d0b3b…。java
//独占锁的接口,如下方法在下面都会详细的介绍
public interface Lock {
//加锁,不支持中断
void lock();
//加锁,支持中断,抛出中断异常
void lockInterruptibly() throws InterruptedException;
//尝试加锁,不支持中断
boolean tryLock();
//在超时时间内获取锁
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
//解锁
void unlock();
//获取条件变量Condition
Condition newCondition();
}复制代码
//Reentrantlock锁的获取和释放都是基于Sync,Sync在ReentrantLock中有两种实现类:NonfairSync(非公平获取锁)、FairSync(公平获取锁),下面会详细介绍Sync
private final Sync sync;复制代码
//无参构造函数,建立ReentrantLock实例,建立非公平的获取锁NonfairSync实例属性
public ReentrantLock() {sync = new NonfairSync();}
/** * 根据传入fair参数,建立非公平的获取锁NonfairSync实例或者公平的获取锁FairSync实例属性 * * @param fair {@code true} 建立FairSync实例属性,false建立NonfairSync实例属性 */
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
复制代码
//AbstractQueuedSynchronizer的实现类,锁的获取和释放都是基于Sync,对AbstractQueuedSynchronizer不清楚的,能够看下另外一篇AbstractQueuedSynchronizer源码分析
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
//抽象方法,由NonfairSync和FairSync进行实现,公平的获取锁,仍是非公平的获取锁
abstract void lock();
//在NonfairSync中使用到,非公平的获取锁
//@param acquires 要获取的锁数
final boolean nonfairTryAcquire(int acquires) {
//获取当前要加锁的线程
final Thread current = Thread.currentThread();
//获取锁的状态,即AQS的属性state值
int c = getState();
//若是锁的状态等于0,表示处于无锁状态
if (c == 0) {
//使用CAS更新锁状态,将锁状态更新成要获取的锁数
if (compareAndSetState(0, acquires)) {
//若是CAS更新锁状态成功,表示获取锁成功,将当前线程设置为占有锁的线程,即设置属性exclusiveOwnerThread为当前线程
setExclusiveOwnerThread(current);
//返回加锁成功
return true;
}
}
//当前锁已被占有,判断占有锁的线程是不是当前线程,若是不是直接返回获取锁失败
else if (current == getExclusiveOwnerThread()) {
//锁的原有状态加上传入进来要获取的锁数获得新的锁状态值
int nextc = c + acquires;
//若是计算出的状态值是负数,直接抛出Error错误,可是感受这里会有些问题,好比原来的锁状态值为1,传入-1也会把锁给释放掉,这样加锁操做就变成了释放锁操做
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
//设置锁的状态值为新的状态值nextc
setState(nextc);
//返回获取锁成功
return true;
}
//返回获取锁失败
return false;
}
//此方法在ReentrantLock的unLock方法中使用到,释放锁,修改锁的状态
//此方法只能在占有锁的线程调用,即unLock方法只能在持有锁的线程进行锁的释放
//@param releases 要释放的锁数
protected final boolean tryRelease(int releases) {
//获得锁的新状态值
int c = getState() - releases;
//若是当前线程不是持有锁的线程,直接抛出IllegalMonitorStateException异常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
//释放锁是否成功的标志位
boolean free = false;
//若是新的锁状态值为0
if (c == 0) {
//将释放锁是否成功的标志位设置为成功
free = true;
//将占有独占锁的线程,即属性exclusiveOwnerThread置为空
setExclusiveOwnerThread(null);
}
//设置锁的状态
setState(c);
//返回释放锁成功
return free;
}
//判断当前线程是不是持有锁的线程,若是是返回true,不然返回false
protected final boolean isHeldExclusively() {
//返回当前线程是不是持有锁的线程
return getExclusiveOwnerThread() == Thread.currentThread();
}
//建立条件变量实例ConditionObject
final ConditionObject newCondition() {
//返回新建的ConditionObject实例
return new ConditionObject();
}
//获取占有锁的线程
final Thread getOwner() {
//若是当前处于无锁状态,返回null,不然返回占有锁的线程
return getState() == 0 ? null : getExclusiveOwnerThread();
}
//获得锁的被获取数,也是锁的状态,只能在持有锁的线程操做才能获取到锁的状态,即锁的被获取数,不然直接返回0
final int getHoldCount() {
//只能在持有锁的线程操做才能获取到锁的状态,即锁的被获取数,不然直接返回0
return isHeldExclusively() ? getState() : 0;
}
//判断锁是否有被线程占有,即锁的状态是不是处于加锁的状态
final boolean isLocked() {
//锁的状态不等于0,代表锁被线程占有,锁状态处于加锁状态
return getState() != 0;
}
//从工做流中获得锁的对象,此方法目前没有使用到
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
//从新设置锁的状态
setState(0); // reset to unlocked state
}
}
复制代码
//Sync的实现类,非公平的获取锁
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
//Sync的抽象lock方法的重写,非公平的获取锁,在Reentrantlock的lock方法使用到
final void lock() {
//使用CAS将锁的状态从0更新成1,即加锁操做
if (compareAndSetState(0, 1))
//若是加锁成功,将当前线程设置为占有锁的线程,即设置属性exclusiveOwnerThread为当前线程
setExclusiveOwnerThread(Thread.currentThread());
else
//NonfairSync从AQS中继承下来的方法,下面在讲锁的获取时会进行详细的介绍
acquire(1);
}
//NonfairSync重写了AbstractQueuedSynchronizer的tryAcquire模板方法,不然AQS中的tryAcquire方法会直接抛出UnsupportedOperationException异常
//tryAcquire方法在acquire中使用到,非公平的获取锁都是基于此方法
//@param acquires 要获取的锁数
protected final boolean tryAcquire(int acquires) {
//nonfairTryAcquire方法,在上面Sync内部中有进行介绍,非公平的获取锁,无需判断同步队列中前面是否有节点也在获取锁
return nonfairTryAcquire(acquires);
}
}复制代码
//Sync的实现类,公平的获取锁
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
//Sync的抽象lock方法的重写,公平的获取锁,在Reentrantlock的lock方法使用到
//FairSync的lock方法和NonfairSync的lock方法的区别是,NonfairSync的lock方法会尝试先获取锁,若是锁获取不到才会调用acquire方法,acquire内部也会尝试再获取锁,若是获取不到加入到同步队列中循环获取锁
final void lock() {
//FairSync 从AQS中继承下来的方法,下面在讲锁的获取时会进行详细的介绍
acquire(1);
}
//NonfairSync重写了AbstractQueuedSynchronizer的tryAcquire模板方法,不然AQS中的tryAcquire方法会直接抛出UnsupportedOperationException异常
//tryAcquire方法在acquire中使用到,公平的获取都是基于此方法
//tryAcquire方法和NonfairSync的tryAcquire方法不一样的是须要调用hasQueuedPredecessors方法,判断头节点的下一个节点的线程是不是当前线程,若是不是代表前面有等待获取锁的线程
//@param acquires 要获取的锁数
protected final boolean tryAcquire(int acquires) {
//获取当前要加锁的线程
final Thread current = Thread.currentThread();
//获取锁的状态,即AQS的属性state值
int c = getState();
//若是锁的状态等于0,表示处于无锁状态
if (c == 0) {
//调用从AQS继承下来的hasQueuedPredecessors方法判断同步队列是否有获取锁的节点的线程,若是是就不执行直接获取锁
if (!hasQueuedPredecessors() &&
//若是AQS同步队列中没有等待要获取锁的节点的线程,使用CAS更新锁的状态
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
//返回公平的获取锁成功
return true;
}
}
//若是当前线程是占有锁的线程
else if (current == getExclusiveOwnerThread()) {
//锁的原有状态加上传入进来要获取的锁数获得新的锁状态值
int nextc = c + acquires;
//若是计算出的状态值是负数,直接抛出Error错误
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
//设置锁的状态值为新的状态值nextc
setState(nextc);
//返回公平的获取锁成功
return true;
}
//返回公平的获取锁失败
return false;
}
}复制代码
//Reentrantlock的lock方法,直到获取独占锁成功,在获取锁的过程当中,线程有可能须要阻塞进入等待状态,不支持中断
public void lock() {
//sync的抽象lock方法,由Sync的两个子类FairSync和NonfairSync对lock进行重写,因为是非公平的获取锁,为此调用的是下面介绍的NonfairSync的重写的lock方法
sync.lock();
}
//NonfairSync重写Sync的lock方法
final void lock() {
//因为是非公平的获取锁,为此先使用CAS将锁的状态从0变成1,即加锁操做
if (compareAndSetState(0, 1))
//将表示占有独占锁的线程属性exclusiveOwnerThread赋值为当前线程
setExclusiveOwnerThread(Thread.currentThread());
else
//调用sync的acquire方法,acquire是AbstractQueuedSynchronizer类中的方法,由sync继承下来
acquire(1);
}
//acquire由Sync从AbstractQueuedSynchronizer类中继承下来的方法
public final void acquire(int arg) {
//tryAcquire方法是个模板方法,AQS中此方法直接抛出UnsupportedOperationException异常,NonfairSync有对AQS中的tryAcquire方法进行实现,NonfairSync的tryAcquire能够看下面介绍
//在调用NonfairSync的tryAcquire方法尝试获取独占锁,若是获取独占锁失败才会调用AQS中的acquireQueued方法循环进行获取独占锁,直到获取独占锁成功
if (!tryAcquire(arg) &&
//addWaiter方法先建立一个要获取独占锁的新节点,加入到同步队列中,acquireQueued死循环的获取独占锁,直到获取独占锁成功
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) //addWaiter、acquireQueued、selfInterrupt方法都是AQS中的方法
//重置线程的中断标志位,能够看下面对selfInterrupt方法的介绍
selfInterrupt();
}
//NonfairSync重写Sync从AQS继承下来的tryAcquire方法
protected final boolean tryAcquire(int acquires) {
//调用Sync中nonfairTryAcquire方法,非公平的尝试获取锁,下面进行介绍
return nonfairTryAcquire(acquires);
}
//Sync的nonfairTryAcquire方法,非公平的获取锁
final boolean nonfairTryAcquire(int acquires) {
//获取当前要加锁的线程
final Thread current = Thread.currentThread();
//获取锁的状态,即AQS的属性state值
int c = getState();
//若是锁的状态等于0,表示处于无锁状态
if (c == 0) {
//使用CAS更新锁状态,将锁状态更新成要获取的锁数
if (compareAndSetState(0, acquires)) {
//若是CAS更新锁状态成功,表示获取锁成功,将当前线程设置为占有锁的线程,即设置属性exclusiveOwnerThread为当前线程
setExclusiveOwnerThread(current);
//返回加锁成功
return true;
}
}
//当前锁已被占有,判断占有锁的线程是不是当前线程,若是不是直接返回获取锁失败
else if (current == getExclusiveOwnerThread()) {
//锁的原有状态加上传入进来要获取的锁数获得新的锁状态值
int nextc = c + acquires;
//若是计算出的状态值是负数,直接抛出Error错误,可是感受这里会有些问题,好比原来的锁状态值为1,传入-1也会把锁给释放掉,这样加锁操做就变成了释放锁操做
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
//设置锁的状态值为新的状态值nextc
setState(nextc);
//返回获取锁成功
return true;
}
//返回获取锁失败
return false;
}
//Sync从AbstractQueuedSynchronizer继承下来的addWaiter方法
//@param mode 要建立节点的模式,是要获取独占锁的节点仍是获取共享锁锁的节点
private Node addWaiter(Node mode) {
//根据当前线程和传入的节点模式建立新节点
Node node = new Node(Thread.currentThread(), mode);
//获取AQS同步队列(CLH)的尾节点
Node pred = tail;
//若是尾节点不为空
if (pred != null) {
//将新建节点的前置节点设置为尾节点
node.prev = pred;
//使用CAS将新建节点设置为尾节点
if (compareAndSetTail(pred, node)) {
//若是CAS成功,尾节点的下一节点为新建节点
pred.next = node;
//返回新建节点
return node;
}
}
//不然调用enq方法进行循环的将新建节点加入同步队列中,作为同步队列的尾节点,详细的能够看enq方法的介绍
enq(node);
//返回新建节点
return node;
}
//Sync从AbstractQueuedSynchronizer继承下来的enq方法,循环的将传入节点加入同步队列中,直到加入加入同步队列为此,作为同步队列的尾节点
private Node enq(final Node node) {
//死循环的将传入节点加入到同步队列中,作为同步队列的尾节点,直到节点加入队列成功为止
for (;;) {
//获取尾节点
Node t = tail;
//若是尾节点为空,代表同步队列不存在节点
if (t == null) {
//新建个节点作为同步队列的头节点,使用CAS进行头节点的设置
if (compareAndSetHead(new Node()))
//若是头节点设置成功,将尾节点设置为头节点
tail = head;
} else {//不然队列不为空
//将新建节点的前置节点设置为尾节点
node.prev = t;
//使用CAS将新建节点设置为尾节点
if (compareAndSetTail(t, node)) {
//若是CAS成功,尾节点的下一节点为新建节点
t.next = node;
//返回新建节点
return t;
}
}
}
}
//Sync从AbstractQueuedSynchronizer中的acquireQueued方法,死循环的获取独占锁,直到获取独占锁成功为此
//@param node 要获取独占锁的节点
//@param arg,要获得独占锁的获取数,arg参数在NonfairSync中的tryAcquire方法使用到
//@return 在获取独占锁的过程当中,是否有发生中断请求
final boolean acquireQueued(final Node node, int arg) {
//在获取独占锁是否失败,若是失败在finally中将节点从同步队列中移除
boolean failed = true;
try {
//线程在获取独占锁阻塞的过程当中是否有其余线程发起中断请求,中断请求的标志位
boolean interrupted = false;
//死循环的获取独占锁,直到获取独占锁成功
for (;;) {
//获取传入节点的前置节点
final Node p = node.predecessor();
//传入节点的前置节点若是为头节点,调用NonfairSync中的重写AQS类中的tryAcquire(arg)方法
if (p == head && tryAcquire(arg)) {
//将传入节点设置为同步队列的头节点
setHead(node);
//传入节点的前置节点的下一节点设置为空
p.next = null; // help GC
//设置获取独占锁成功标志位
failed = false;
//返回当前线程在获取独占锁的过程当中是否有发生中断标志位
return interrupted;
}
//shouldParkAfterFailedAcquire方法在上一次获取独占锁失败时,是否须要阻塞,根据当前节点的前置节点状态来判断,详细的能够看下面的介绍
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt()) //parkAndCheckInterrupt方法阻塞当前线程,而且在当前线程被唤醒时,检查当前线程是否被中断,parkAndCheckInterrupt返回中断标志位,详细的能够看下面的介绍
//parkAndCheckInterrupt返回线程在阻塞被唤醒时,线程是否被中断的标志位
interrupted = true;
}
} finally {
//若是获取独占锁失败
if (failed)
//若是获取独占锁失败,从同步队列中移除当前节点,根据当前节点的前置节点状态是否唤醒当前节点的不为空的下一节点线程,cancelAcquire方法能够看下面详细介绍
cancelAcquire(node);
}
}
//AbstractQueuedSynchronizer中的selfInterrupt方法
static void selfInterrupt() {
//设置当前线程的中断标志位
Thread.currentThread().interrupt();
}
//Sync从AbstractQueuedSynchronizer继承下来的shouldParkAfterFailedAcquire方法
//即线程在上一次没有获取到独占锁,再次获取独占锁时是否须要阻塞
//@param pred 传入节点node的前置节点
//@param node 要获取独占锁的节点
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
//获取前置节点的状态,若是对AQS状态不清楚的能够看下另外一篇AQS源码分析
int ws = pred.waitStatus;
//若是前置节点的状态为Node.SIGNAL,SIGNAL状态表示下一节点须要阻塞
if (ws == Node.SIGNAL)
//返回当前要获取独占锁的节点须要阻塞
return true;
//若是当前要获取独占锁的节点的前置节点已取消CANCELLED,从新获取有效的前置节点
if (ws > 0) {
do {
//从新设置要获取独占锁节点的前置节点
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);//循环获取前面有效的前置节点,CLH队列必定会有个有效的头节点
//有效的前置节点的下一节点设置为当前要获取独占锁的节点
pred.next = node;
} else {
//不然将前置节点的状态设置为Node.SIGNAL,在下一次循环时,将其要获取独占锁的节点阻塞
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
//返回不须要阻塞要获取独占锁的节点的线程
return false;
}
//Sync从AbstractQueuedSynchronizer继承下来的parkAndCheckInterrupt方法
private final boolean parkAndCheckInterrupt() {
//阻塞当前线程,this是监控对象,这样能够知道当前线程是被那个对象阻塞
LockSupport.park(this);
//线程被唤醒时,判断在等待的过程当中是否有中断请求
return Thread.interrupted();
}
//Sync从AbstractQueuedSynchronizer中的cancelAcquire方法
//将传入节点从同步队列中移除,若是要移除节点为尾节点,从新设置尾节点,若是要移除节点的前置节点为头节点,唤醒要取消节点的下一节点
//@param node 要取消的节点
private void cancelAcquire(Node node) {
//若是传入的要取消节点为空,直接退出
if (node == null)
//直接退出
return;
//将要取消节点的线程置为空
node.thread = null;
//获取要取消节点的前置节点
Node pred = node.prev;
//循环获取不是取消的前置节点节点
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
//获取前置节点的下一个节点,在下面cas须要使用到
Node predNext = pred.next;
//将要取消节点的状态设置为取消Node.CANCELLED状态
node.waitStatus = Node.CANCELLED;
//若是要取消节点为尾节点,将其尾节点设置为有效的前置节点
if (node == tail && compareAndSetTail(node, pred)) {
//将有效的前置节点的下一节点设置为空
compareAndSetNext(pred, predNext, null);
} else {
//不然的话根据有效的前置节点状态和是否头节点来判断是否须要唤醒要取消节点的下一节点
int ws;
//有效的前置节点不是头节点
if (pred != head &&
//有效的前置节点状态为Node.SIGNAL,或者使用cas将有效的前置节点的状态设置为Node.SIGNAL,而且有效的前置节点的线程不为空
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
//获取要取消节点的下一个节点
Node next = node.next;
//要取消节点的下一个节点不为空,而且不是已取消状态
if (next != null && next.waitStatus <= 0)
//将要取消节点的下一个节点和有效的前置节点链接起来
compareAndSetNext(pred, predNext, next);
} else {
//唤醒要取消节点的下一个节点unparkSuccessor方法能够看下面
unparkSuccessor(node);
}
//将要取消节点的下一个节点设置为自身
node.next = node; // help GC
}
}
//Sync从AbstractQueuedSynchronizer中的unparkSuccessor方法
//唤醒当前传入节点的下一个不为空而且不是取消的节点线程
//@param node 唤醒传入节点下一节点
private void unparkSuccessor(Node node) {
//传入节点的状态
int ws = node.waitStatus;
//若是传入节点的状态小于0,即SIGNAL或者PROPAGATE
if (ws < 0)
//使用CAS将传入节点的状态设置为0
compareAndSetWaitStatus(node, ws, 0);
//获取传入节点的下一节点
Node s = node.next;
//若是下一节点为空,或者是已取消状态
if (s == null || s.waitStatus > 0) {
//将下一节点设置为空
s = null;
//从尾节点开始寻找传入节点有效的下一节点(不为空,而且不是已取消状态)
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
//若是下一个有效节点不为空,而且不是已取消状态,唤醒此节点对应的线程
if (s != null)
//唤醒下一节点的线程
LockSupport.unpark(s.thread);
}
//Reentrantlock的lockInterruptibly方法,直到获取独占锁成功或者在获取锁的过程当中,线程有可能须要阻塞进入等待状态,在等待被唤醒时,若是线程被中断,直接抛出中断异常,支持中断
//和Reentrantlock的lock方法的差异,在获取独占锁阻塞等待被唤醒时,线程被中断,抛出中断异常
public void lockInterruptibly() throws InterruptedException {
//调用sync从AQS中继承下来的acquireInterruptibly方法,能够看下面对此方法的介绍
sync.acquireInterruptibly(1);
}
//Sync从AbstractQueuedSynchronizer继承下来的acquireInterruptibly方法
//@param arg 要获取独占锁的获取数
public final void acquireInterruptibly(int arg) throws InterruptedException {
//要获取独占锁的线程被中断,抛出中断异常
if (Thread.interrupted())
throw new InterruptedException();
//tryAcquire方法是个模板方法,AQS中此方法直接抛出UnsupportedOperationException异常,NonfairSync有对AQS中的tryAcquire方法进行实现,NonfairSync的tryAcquire能够看下面介绍
//在调用NonfairSync的tryAcquire方法尝试获取独占锁,若是获取独占锁失败才会调用AQS中的doAcquireInterruptibly方法循环进行获取独占锁,直到获取独占锁成功或者线程被中断抛出中断异常
if (!tryAcquire(arg))
//若是调用tryAcquire方法失败,调用sync从AQS中继承下来的doAcquireInterruptibly方法,能够看下面对此方法的介绍
doAcquireInterruptibly(arg);
}
//Sync从AbstractQueuedSynchronizer继承下来的doAcquireInterruptibly方法,和上面介绍的acquireQueued方法惟一不一样是,在线程Wait被唤醒时,检测线程是否被中断,若是被中断直接抛出中断异常
private void doAcquireInterruptibly(int arg) throws InterruptedException {
//根据当前线程和独占模式建立新节点,addWaiter方法能够看上面的介绍
final Node node = addWaiter(Node.EXCLUSIVE);
//在获取独占锁是否失败,若是失败在finally中将节点从同步队列中移除
boolean failed = true;
try {
//死循环的获取独占锁,直到获取独占锁成功或者抛出中断异常
for (;;) {
//获取新建节点的前置节点
final Node p = node.predecessor();
//新建节点的前置节点若是为头节点,调用NonfairSync中重写AQS类中的tryAcquire(arg)方法
if (p == head && tryAcquire(arg)) {
//将新建节点设置为同步队列的头节点
setHead(node);
//新建节点的前置节点的下一节点设置为空
p.next = null; // help GC
//设置获取独占锁成功标志位
failed = false;
//直接退出
return;
}
//shouldParkAfterFailedAcquire方法在上一次获取独占锁失败时,是否须要阻塞,根据当前节点的前置节点状态来判断,详细的能够看上面的介绍
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt()) //parkAndCheckInterrupt方法阻塞当前线程,而且在当前线程被唤醒时,检查当前线程是否被中断,parkAndCheckInterrupt返回中断标志位,详细的能够看上面的介绍
//parkAndCheckInterrupt返回线程在等待被唤醒时,线程是否被中断的标志位,线程被中断抛出中断异常
throw new InterruptedException();
}
} finally {
//若是获取独占锁失败
if (failed)
//若是获取独占锁失败,从同步队列中移除当前节点,根据当前节点的前置节点状态是否唤醒当前节点的不为空的下一节点线程,cancelAcquire方法能够看上面详细介绍
cancelAcquire(node);
}
}
//Reentrantlock的tryLock方法,尝试获取独占锁,获取不到直接返回,不会加入同步队列中,不支持中断
public boolean tryLock() {
////调用在Sync介绍的nonfairTryAcquire方法
return sync.nonfairTryAcquire(1);
}
//Reentrantlock的tryLock(long timeout, TimeUnit unit)方法,超时的获取独占锁,支持中断,若是线程在获取独占锁的过程当中,被中断,抛出中断异常
//和Reentrantlock的lock方法的区别是支持超时的获取锁,获取不到直接返回获取独占锁失败,lock要获取到独占锁才会退出,lock方法不会抛出中断异常
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
//调用sync从AQS中继承下来的tryAcquireNanos方法,能够看下面对此方法的介绍
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
//Sync从AbstractQueuedSynchronizer继承下来的tryAcquireNanos方法
//@param arg 要获取独占锁的获取数
public final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException {
//要获取独占锁的线程被中断,抛出中断异常
if (Thread.interrupted())
//抛出中断异常
throw new InterruptedException();
//tryAcquire方法是个模板方法,AQS中此方法直接抛出UnsupportedOperationException异常,NonfairSync有对AQS中的tryAcquire方法进行实现,NonfairSync的tryAcquire能够看下面介绍
//在调用NonfairSync的tryAcquire方法尝试获取独占锁,若是获取独占锁失败才会调用AQS中的doAcquireNanos方法循环进行获取独占锁,直到获取独占锁成功或者超时退出或者线程被中断抛出中断异常
return tryAcquire(arg) ||
//若是调用tryAcquire方法失败,调用sync从AQS中继承下来的doAcquireInterruptibly方法,能够看下面对此方法的介绍
doAcquireNanos(arg, nanosTimeout);
}
//@param arg 要获取独占锁的获取数
//@param nanosTimeout 获取独占锁的超时时间,若是超时返回获取独占锁失败
//@thorws InterruptedException 线程在获取独占锁的线程被中断,抛出中断异常
private boolean doAcquireNanos(int arg, long nanosTimeout) throws InterruptedException {
//若是超时时间小于等于0,直接返回获取独占锁失败
if (nanosTimeout <= 0L)
//返回获取独占锁失败
return false;
//当前时间加上超时时间,获得获取独占锁线程的死亡时间
final long deadline = System.nanoTime() + nanosTimeout;
//根据当前线程和独占模式建立新节点,addWaiter方法能够看上面的介绍
final Node node = addWaiter(Node.EXCLUSIVE);
//在获取独占锁是否失败,若是失败在finally中将节点从同步队列中移除
boolean failed = true;
try {
//死循环的获取独占锁,直到获取独占锁成功或者抛出中断异常
for (;;) {
//获取新建节点的前置节点
final Node p = node.predecessor();
//新建节点的前置节点若是为头节点,调用NonfairSync中重写AQS类中的tryAcquire(arg)方法
if (p == head && tryAcquire(arg)) {
//将新建节点设置为同步队列的头节点
setHead(node);
//新建节点的前置节点的下一节点设置为空
p.next = null; // help GC
//设置获取独占锁成功标志位
failed = false;
//返回获取独占锁成功
return true;
}
//死亡时间减去当前时间,获得新的超时时间
nanosTimeout = deadline - System.nanoTime();
//若是新的超时时间小于等于0,直接返回获取独占锁失败
if (nanosTimeout <= 0L)
//返回获取独占锁失败
return false;
//shouldParkAfterFailedAcquire方法在上一次获取独占锁失败时,是否须要阻塞,根据当前节点的前置节点状态来判断,详细的能够看上面的介绍
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold) //超时时间须要大于AQS属性spinForTimeoutThreshold值,才会阻塞线程,不然让其线程自旋一段时间获取独占锁
//模拟让线程等待必定时间,unpark唤醒或者超时自动唤醒
LockSupport.parkNanos(this, nanosTimeout);
//判断当前获取独占锁的线程是否被中断
if (Thread.interrupted())
//若是被中断抛出中断异常
throw new InterruptedException();
}
} finally {
//若是获取独占锁失败
if (failed)
//若是获取独占锁失败,从同步队列中移除当前节点,根据当前节点的前置节点状态是否唤醒当前节点的不为空的下一节点线程,cancelAcquire方法能够看上面详细介绍
cancelAcquire(node);
}
}
复制代码
//Reentrantlock的lock方法,sync属性为FairSync
public void lock() {
//sync的抽象lock方法,由Sync的两个子类FairSync和NonfairSync对lock进行重写,因为是公平的获取独占锁,为此调用的是下面介绍的FairSync的重写的lock方法
sync.lock();
}
//FairSync重写Sync的lock方法,与NonfairSync重写Sync的lock方法不同的是,直接调用acquire方法进行获取独占锁,NonfairSync的lock方法首先会使用cas尝试加锁
final void lock() {
//调用sync的acquire方法,acquire是AbstractQueuedSynchronizer类中的方法,由sync继承下来,看下面对此方法的介绍
acquire(1);
}
//acquire由Sync从AbstractQueuedSynchronizer类中继承下来的方法
public final void acquire(int arg) {
//tryAcquire方法是个模板方法,AQS中此方法直接抛出UnsupportedOperationException异常,FairSync有对AQS中的tryAcquire方法进行实现,FairSync的tryAcquire能够看下面介绍
//在调用FairSync的tryAcquire方法尝试获取独占锁,若是获取独占锁失败才会调用AQS中的acquireQueued方法循环进行获取独占锁,直到获取独占锁成功
if (!tryAcquire(arg) &&
//addWaiter方法先建立一个要获取独占锁的新节点,加入到同步队列中,acquireQueued死循环的获取独占锁,直到获取独占锁成功
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) //addWaiter、acquireQueued、selfInterrupt方法都是AQS中的方法,在上面非公平的获取独占锁有对这些方法进行介绍
//重置线程的中断标志位,在非公平的获取独占锁有对selfInterrupt方法进行介绍,详细的能够看上面
selfInterrupt();
}
//FairSync重写Sync从AQS继承下来的tryAcquire方法
protected final boolean tryAcquire(int acquires) {
//获取当前要加锁的线程
final Thread current = Thread.currentThread();
//获取锁的状态,即AQS的属性state值
int c = getState();
//若是锁的状态等于0,表示处于无锁状态
if (c == 0) {
//调用从AQS继承下来的hasQueuedPredecessors方法判断同步队列是否有获取锁的节点的线程,若是是就不执行直接获取锁
if (!hasQueuedPredecessors() &&
//若是AQS同步队列中没有等待要获取锁的节点的线程,使用CAS更新锁的状态
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
//返回公平的获取锁成功
return true;
}
}
//若是当前线程是占有锁的线程
else if (current == getExclusiveOwnerThread()) {
//锁的原有状态加上传入进来要获取的锁数获得新的锁状态值
int nextc = c + acquires;
//若是计算出的状态值是负数,直接抛出Error错误
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
//设置锁的状态值为新的状态值nextc
setState(nextc);
//返回公平的获取锁成功
return true;
}
//返回公平的获取锁失败
return false;
}
//sync从AbstractQueuedSynchronizer类中继承下来的hasQueuedPredecessors方法
public final boolean hasQueuedPredecessors() {
//获取AQS中的同步队列尾节点
Node t = tail;
//获取AQS中的同步队列头节点
Node h = head;
Node s;
//若是同步队列的头尾节点不相等,而且头节点的下一节点等于空,代表同步队列中存在要获取独占锁的节点,或者同步队列的头节点的下一节点中的线程不是当前线程,返回true,须要阻塞
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
//Reentrantlock的lockInterruptibly方法,直到获取独占锁成功或者在获取锁的过程当中,线程有可能须要阻塞进入等待状态,在等待被唤醒时,若是线程被中断,直接抛出中断异常,支持中断
//和Reentrantlock的lock方法的差异,在获取独占锁阻塞等待被唤醒时,线程被中断,抛出中断异常
public void lockInterruptibly() throws InterruptedException {
//调用sync从AQS中继承下来的acquireInterruptibly方法,acquireInterruptibly在上面非公平的获取独占锁有对其进行介绍,只是内部调用tryAcquire是FairSync重写的tryAcquire方法,其余都同样,不清楚的能够看上面
sync.acquireInterruptibly(1);
}
//Reentrantlock的tryLock方法,尝试获取独占锁,获取不到直接返回,不会加入同步队列中,不支持中断
public boolean tryLock() {
//调用在Sync介绍的nonfairTryAcquire方法
return sync.nonfairTryAcquire(1);
}
//Reentrantlock的tryLock(long timeout, TimeUnit unit)方法,超时的获取独占锁,支持中断,若是线程在获取独占锁的过程当中,被中断,抛出中断异常
//和Reentrantlock的lock方法的区别是支持超时的获取锁,获取不到直接返回获取独占锁失败,lock要获取到独占锁才会退出,lock方法不会抛出中断异常
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
//调用sync从AQS中继承下来的tryAcquireNanos方法,tryAcquireNanos在上面非公平的获取独占锁有对其进行介绍,只是内部调用tryAcquire是FairSync重写的tryAcquire方法,其余都同样,不清楚的能够看上面
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
复制代码
//Reentrantlock的unlock方法,释放独占锁
public void unlock() {
//调用Sync从AQS中继承下来的release方法,详细的能够看下面的介绍
sync.release(1);
}
//sync从AbstractQueuedSynchronizer类中继承下来的release
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
//若是头节点不为空,而且状态不是0,状态是0的话,后面的节点都不会阻塞为此不用唤醒
if (h != null && h.waitStatus != 0)
//Sync从AbstractQueuedSynchronizer中的unparkSuccessor方法
//唤醒当前传入节点的下一个不为空而且不是取消的节点线程
unparkSuccessor(h);
//返回释放独占锁成功
return true;
}
//返回释放独占锁失败
return false;
}
//sync的tryRelease方法
//此方法只能在占有锁的线程调用,即unLock方法只能在持有锁的线程进行锁的释放
//@param releases 要释放的锁数
protected final boolean tryRelease(int releases) {
//获得锁的新状态值
int c = getState() - releases;
//若是当前线程不是持有锁的线程,直接抛出IllegalMonitorStateException异常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
//释放锁是否成功的标志位
boolean free = false;
//若是新的锁状态值为0
if (c == 0) {
//将释放锁是否成功的标志位设置为成功
free = true;
//将占有独占锁的线程,即属性exclusiveOwnerThread置为空
setExclusiveOwnerThread(null);
}
//设置锁的状态
setState(c);
//返回释放锁成功
return free;
}复制代码