图解AQS原理之ReentrantLock详解-非公平锁 (5)

再次进入到方法之后发现前驱节点的waitStatus=-1,表示当前节点需要进行挂起等到,此时返回的结果是true,则会运行parkAndCheckInterrupt方法,这个方法很简单就是将当前线程进行挂起操作,如下所示:

private final boolean parkAndCheckInterrupt() { LockSupport.park(this); //挂起线程 return Thread.interrupted(); //判断是否被中断,获取中断标识 }

park挂起线程并且响应中断信息,其实我们从这里就能发现一个问题,Thread.interrupted方法是用来获取是否被中断的标志,如果被中断则返回true,如果没有被中断则返回false,当当前节点被中断后,其实就会返回true,返回true这里并没有结束,而是跳到调用地方,也就是acquireQueued方法内部:

if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true;

以一个案例来进行分析:

public class ReentrantLockDemo { public static void main(String[] args) throws Exception { AddDemo runnalbeDemo = new AddDemo(); Thread thread = new Thread(runnalbeDemo::add); thread.start(); Thread thread1 = new Thread(runnalbeDemo::add); thread1.start(); Thread thread2 = new Thread(runnalbeDemo::add); thread2.start(); Thread.sleep(10000); thread1.interrupt(); System.out.println(runnalbeDemo.getCount()); } private static class AddDemo { private final AtomicInteger count = new AtomicInteger(); private final ReentrantLock reentrantLock = new ReentrantLock(); private final Condition condition = reentrantLock.newCondition(); private void add() { try { reentrantLock.lock(); count.getAndIncrement(); } finally { // reentrantLock.unlock(); } } int getCount() { return count.get(); } } }

通过上面的例子可以发现,thread1调用中断方法interrupt(),当调用第一次方法的时候,它会进入到parkAndCheckInterrupt方法,然后线程响应中断,最后返回true,最后返回到acquireQueued方法内部,整个if语句为true,则开始设置interrupted=true,仅仅是设置了等于true,但是这离还会进入下一轮的循环,假如说上次的线程没有完成任务,则没有获取到锁,还是会进入到shouldParkAfterFailedAcquire由于已经修改了上一个节点的waitStatus=-1,直接返回true,然后再进入到parkAndCheckInterrupt又被挂起线程,但是如果上步骤操作他正抢到锁,则会返回ture,外面也会清除中断标志位,从这里可以清楚地看到acquire方法是一个不间断获得锁的操作,可能重复阻塞和解除阻塞操作。

上面阻塞队列的内容已经讲完了,接下来我们看一下unlock都为我们做了什么工作:

public void unlock() { sync.release(1); }

我们可以看到他直接调用了独占模式的release方法,看一下具体源码:

public final boolean release(int arg) { if (tryRelease(arg)) { //调用ReentrantLock中的Sync里面的tryRelease方法 Node h = head; //获取头节点 if (h != null && h.waitStatus != 0) //头节点不为空且状态不为0时进行unpark方法 unparkSuccessor(h); //唤醒下一个未被取消的节点 return true; } return false; }

release方法,首先先进行尝试去释放锁,如果释放锁仍然被占用则直接返回false,如果尝试释放锁时,发现锁已经释放,当前线程不在占用锁资源时,则会进入的下面进行一些列操作后返回true,接下来我们先来看一下ReentrantLock的Sync下的tryRelease方法,如下所示:

protected final boolean tryRelease(int releases) { int c = getState() - releases; //获取state状态,标志信息减少1 if (Thread.currentThread() != getExclusiveOwnerThread()) //线程不一致抛出异常 throw new IllegalMonitorStateException(); boolean free = false; //是否已经释放锁 if (c == 0) { //state=0时表示锁已经释放 free = true; //将标志free设置为true setExclusiveOwnerThread(null); //取消独占锁信息 } setState(c); //设置锁标志信息 return free; }

看上面的源码,表示首先先获取state状态,如果state状态减少1之后和0不相等则代表有重入锁,则表示当前线程还在占用所资源,直到线程释放锁返回ture标识,还是以上例子为主(此时AddDemo中的unlock不在被注释),分析其现在的队列中的状态

图解AQS原理之ReentrantLock详解-非公平锁

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyffxz.html