写在前边:阅读本文前推荐阅读Java中的锁(2),本文为该篇的延续。
3.共享式获取锁和释放锁
●共享式获取锁和独占式获取锁的主要区别在于在同一时刻能否有多个线程同时获得同步状态。通过调用同步器的acquireShared(int arg)方法可以共享式获取同步状态。
public final void acquireShared(int arg) {
if(tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
private void doAcquireShared(int arg) {
//加入尾部队列
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
复制代码
-
1.tryAcquireShared(int arg)方法尝试获取同步状态,且返回值为int型,当返回值大于等于0时,表示获取同步状态成功;若返回值小于0,则进入doAcquireShared(int arg)方法。
-
2.在doAcquireShared(int arg)自旋的过程中,只有当前节点的前驱节点为头结点,才能尝试获取同步状态。若获取同步状态成功,则从自旋中退出。
●共享式锁通过调用releaseShared(int arg)方法释放同步状态。
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
复制代码
- 1.该方法在释放同步状态成功后会唤醒后续处于等待状态的节点。
- 2.因为可能存在多个线程同时释放同步状态的情况,tryReleaseShared(int arg)通过循环CAS的方法确保同步状态量能线程安全释放。
4. 独占式超时获取同步状态
●对于synchronized关键字来说,当线程因获取不到锁而synchronized被阻塞时,对线程进行中断,此时线程的中断标志位会被修改,当线程依旧阻塞,无法响应中断。
●对于同步器提供的acquireInterruptibly(int arg)方法来说,调用这个方法的线程因无法获得同步状态而阻塞在同步队列上时,仍然能够响应中断,响应中断的方式为抛出InterruptedException异常。
●超时获取同步状态的的过程可以视为可中断获取同步状态的"增强版",doAcquireNanos(int arg,long nanosTimeout)方法在支持中断响应的基础上,增加了超时等待的功能。
转载于:https://juejin.im/post/5d00d077e51d4510926a7b37