@@ -154,7 +154,9 @@ public Semaphore(int permits, boolean fair) {
154154
155155` Semaphore ` 是共享锁的一种实现,它默认构造 AQS 的 ` state ` 值为 ` permits ` ,你可以将 ` permits ` 的值理解为许可证的数量,只有拿到许可证的线程才能执行。
156156
157- 调用` semaphore.acquire() ` ,线程尝试获取许可证,如果 ` state >= 0 ` 的话,则表示可以获取成功。如果获取成功的话,使用 CAS 操作去修改 ` state ` 的值 ` state=state-1 ` 。如果 ` state<0 ` 的话,则表示许可证数量不足。此时会创建一个 Node 节点加入阻塞队列,挂起当前线程。
157+ 调用` semaphore.acquire() ` ,线程尝试获取许可证,如果 ` state > 0 ` 的话,则表示可以获取成功,如果 ` state <= 0 ` 的话,则表示许可证数量不足,获取失败。
158+
159+ 如果可以获取成功的话(` state > 0 ` ),会尝试使用 CAS 操作去修改 ` state ` 的值 ` state=state-1 ` 。如果获取失败则会创建一个 Node 节点加入阻塞队列,挂起当前线程。
158160
159161``` java
160162/**
@@ -170,13 +172,40 @@ public final void acquireSharedInterruptibly(int arg)
170172 throws InterruptedException {
171173 if (Thread . interrupted())
172174 throw new InterruptedException ();
173- // 尝试获取许可证,arg为获取许可证个数,当可用许可证数减当前获取的许可证数结果小于0 ,则创建一个节点加入阻塞队列,挂起当前线程。
175+ // 尝试获取许可证,arg为获取许可证个数,当获取失败时 ,则创建一个节点加入阻塞队列,挂起当前线程。
174176 if (tryAcquireShared(arg) < 0 )
175177 doAcquireSharedInterruptibly(arg);
176178}
179+ /**
180+ * 共享模式下尝试获取资源(在Semaphore中的资源即许可证):
181+ * 1、获取失败,返回负值
182+ * 2、共享模式下获取成功,但后续的共享模式获取会失败,返回0
183+ * 3、共享模式获取成功,随后的共享模式也可能获取成功,返回正值
184+ */
185+ protected int tryAcquireShared(int acquires) {
186+ return nonfairTryAcquireShared(acquires);
187+ }
188+ /**
189+ * 非公平的共享模式获取许可证,acquires为许可证数量,根据代码上下文可知该值总是为1
190+ * 注:公平模式的实现会先判断队列中是否有节点在排队,有则直接返回-1,表示获取失败,没有则执行下面的操作
191+ */
192+ final int nonfairTryAcquireShared(int acquires) {
193+ for (;;) {
194+ // 当前可用许可证数量
195+ int available = getState();
196+ /*
197+ * 尝试获取许可证,当前可用许可证数量小于等于0时,返回负值,表示获取失败,
198+ * 当前可用许可证大于0时才可能获取成功,CAS失败了会循环重新获取最新的值尝试获取
199+ */
200+ int remaining = available - acquires;
201+ if (remaining < 0 ||
202+ compareAndSetState(available, remaining))
203+ return remaining;
204+ }
205+ }
177206```
178207
179- 调用` semaphore.release(); ` ,线程尝试释放许可证,并使用 CAS 操作去修改 ` state ` 的值 ` state=state+1 ` 。释放许可证成功之后,同时会唤醒同步队列中的一个线程。被唤醒的线程会重新尝试去修改 ` state ` 的值 ` state=state-1 ` ,如果 ` state>= 0 ` 则获取令牌成功,否则重新进入阻塞队列,挂起线程。
208+ 调用` semaphore.release(); ` ,线程尝试释放许可证,并使用 CAS 操作去修改 ` state ` 的值 ` state=state+1 ` 。释放许可证成功之后,同时会唤醒同步队列中的一个线程。被唤醒的线程会重新尝试去修改 ` state ` 的值 ` state=state-1 ` ,如果 ` state > 0 ` 则获取令牌成功,否则重新进入阻塞队列,挂起线程。
180209
181210``` java
182211// 释放一个许可证
@@ -194,6 +223,17 @@ public final boolean releaseShared(int arg) {
194223 }
195224 return false ;
196225}
226+ // 尝试释放资源
227+ protected final boolean tryReleaseShared(int releases) {
228+ for (;;) {
229+ int current = getState();
230+ int next = current + releases; // 可用许可证+1
231+ if (next < current) // overflow
232+ throw new Error (" Maximum permit count exceeded" );
233+ if (compareAndSetState(current, next)) // 通过CAS修改
234+ return true ;
235+ }
236+ }
197237```
198238
199239#### 实战
0 commit comments