<p> </p>
<blockquote>
<p>AQS 系列:</p>
<ul><li><a href="https://blog.csdn.net/weixin_43935927/article/details/108693296">【JUC源码】JUC核心:AQS(一)底层结构分析</a></li><li><a href="https://blog.csdn.net/weixin_43935927/article/details/113901484">【JUC源码】JUC核心:AQS(二)同步队列源码分析(独占锁)</a></li><li><a href="https://blog.csdn.net/weixin_43935927/article/details/113904384">【JUC源码】JUC核心:AQS(三)同步队列源码分析(共享锁)</a></li><li><a href="https://blog.csdn.net/weixin_43935927/article/details/113901502">【JUC源码】JUC核心:AQS(四)条件队列源码分析</a></li><li><a href="https://blog.csdn.net/weixin_43935927/article/details/108699927">【JUC源码】JUC核心:关于AQS的几个问题</a></li></ul>
</blockquote>
<p>同步队列:</p>
<ul><li>作用:管理多个线程的休眠与唤醒</li><li>策略:可以执行的线程 = RUNNABLE 状态 && tryAcquire() 成功
<ul><li>独占模式(EXCLUSIVE):队首持锁,唤醒队二后 tryAcquire() 尝试拿锁,队三及以后休眠</li><li>共享模式(SHARED):相较于独占模式只唤醒队二 ,共享模式还唤醒所有 mode=shared 节点(多了一步)<br> 注:这里需要明确一点,独占和共享是<strong>对于加锁而言</strong>(能否多线程同时获锁),释放锁时没有独占和共享的概念</li></ul></li><li>状态
<ul><li>初始化(0):入队的初始状态</li><li>SIGINAL(-1):若当前 node 后面还有 node,就要从 0->SIGNAL</li><li>CANCELLED(1):拿锁失败或出现异常,会在置为 CANCELLED 后删除,但并发时可能会暂时维持</li></ul></li></ul>
<h2><a name="t0"></a><a id="1_19"></a>1.独占-加锁</h2>
<h3><a name="t1"></a><a id="acquire_20"></a>acquire()</h3>
<p>该方法用作获取锁。排他模式下,acquire 方法由子类的 lock 方法直接调用。如下图是 Reentrantlock 的静态内部类 Sync 和 NonfairSync:</p>
<p><img alt="在这里插入图片描述" src="https://beijingoptbbs.oss-cn-beijing.aliyuncs.com/cs/5606289-3818b7d97c723bd3b1f55d5511ca83c6"></p>
<p><img alt="在这里插入图片描述" src="https://beijingoptbbs.oss-cn-beijing.aliyuncs.com/cs/5606289-b3a10e5ded6c29171784866187e82c21.png"><br> 注:从图中也可以看出 NonfairSync 的 lock 方法是<strong>非公平</strong>的,因为当前线程直接就有获取锁的机会(CAS修改state成功),不是必须要进入同步队列,接受同步器的调度。</p>
<ul><li>尝试获得锁,成功直接放回</li><li>失败,加入同步队列,等待拿锁</li></ul>
<pre class="blockcode"><code>public final void acquire(int arg) {
// tryAcquire 方法是需要子类去实现的
// CAS修改state判断能否拿到锁,拿到锁return true,不会再进入addWaiter
if (!tryAcquire(arg) &&
// addWaiter 入参代表是排他模式
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
</code></pre>
<blockquote>
<p>PS:这里一定要明白,AQS 中并没有实现 tryAcquire() 方法,它是交由子类去实现的,因为它是使用 AQS 加锁的关键。</p>
</blockquote>
<p>如下图,是 Reentrantlock中 NonfairSync 的 tryAcquire 方法的具体实现</p>
<p><img alt="在这里插入图片描述" src="https://beijingoptbbs.oss-cn-beijing.aliyuncs.com/cs/5606289-38273bd24ba87100688f2e9740d0f0b6"></p>
<pre class="blockcode"><code>// Reentrantlock.sync#nonfairTryAcquire()
final boolean nonfairTryAcquire(int acquires) {
// 获取当前线程
final Thread current = Thread.currentThread();
// 获取当前同步器的状态
int c = getState();
// 若c=0,表示没有线程持锁,即有机会获取锁
if (c == 0) {
// 尝试将state通过CAS设置为1
if (compareAndSetState(0, acquires)) {
// 若CAS成功,表示当前线程可以拿锁,则将拿锁线程设为当前
setExclusiveOwnerThread(current);
return true; // 返回true
}
}
// 如果当前线程已经获得锁了
else if (current == getExclusiveOwnerThread()) {
// 重入,+1
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
// 返回true
return true;
}
// 否则,返回false,表示获取不到锁
return false;
}
</code></pre>
<h3><a name="t2"></a><a id="addWaiter_80"></a>addWaiter()</h3>
<p>回到 acquire() ,可以看到 tryAcquire() 后,就是 addWaiter(),将等待的线程加入同步队列。</p>
<blockquote>
<p>PS:这里注意一点,对于同步队列节点的所有操作,都要是线程安全的,即通过 CAS</p>
</blockquote>
<pre class="blockcode"><code>private Node addWaiter |
|