一、简介
Reentrantlock是并发包中可重入的独占锁,只能有一个线程占有锁,锁的获取和释放是基于AQS(AbstractQueuedSynchronized)实现的, 有公平和不公平两种获取锁的实现方式。Reentranlock 中有一个内部抽象类Sync继承自AbstractQueuedSynchronized, 主要是它来实现锁获取和释放的功能,Sync 在ReentrantLock中有两种实现类:NonfairSync(非公平获取锁)、FairSync(公平获取锁), Reentrantlock支持Condition,AQS中有同步队列和条件队列,不清楚的,可以看下我的另一篇AbstractQueuedSynchronized的源码分析juejin.cn/post/684490…。
二、类关系
//独占锁的接口,以下方法在下面都会详细的介绍
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();
}
五、内部类
- Sync内部类
//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 } }
- NonfairSync内部类
//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); } }
- FairSync内部类
//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; }