Java并发编程系列-AbstractQueuedSynchronizer (10)

一般来说这里唤醒的主要目的是为了唤醒一个共享式获取同步状态的线程节点,它会直接获取到同步状态;但也存在特殊情况,比如
这个节点线程被取消了,导致唤醒了一个独享式获取的线程节点,那么在这个线程被唤醒后尝试独享式获取同步状态的时候会获取不到
(因为同步状态被共享式获取的线程持久,而且可能是多个)从而再次进入阻塞。

其实唤醒的主要来源还是靠同步状态释放操作来发起的。

acquireSharedInterruptibly(int)

该方法表示共享式获取同步状态,响应中断,源码如下:

public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable { public final void acquireSharedInterruptibly(int arg) throws InterruptedException { // 首先响应中断 if (Thread.interrupted()) throw new InterruptedException(); // 尝试共享式获取同步状态,失败则执行doAcquireSharedInterruptibly方法 if (tryAcquireShared(arg) < 0) doAcquireSharedInterruptibly(arg); } // 可中断的共享式获取同步状态 private void doAcquireSharedInterruptibly(int arg) throws InterruptedException { // 首先封装线程节点,保存到同步队列尾部 final Node node = addWaiter(Node.SHARED); boolean failed = true; try { for (;;) {// 自旋 final Node p = node.predecessor();// 获取前置节点 if (p == head) { int r = tryAcquireShared(arg); if (r >= 0) { setHeadAndPropagate(node, r); p.next = null; // help GC failed = false; return; } } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) // 如果发生了中断则抛出异常 throw new InterruptedException(); } } finally { if (failed) cancelAcquire(node); } } }

解析:这个方法与acquireShared几乎一致,仅仅是在处理中断的问题上有点区别,所以不再赘述。

tryAcquireSharedNanos(int, long)

该方法表示共享式获取同步状态,响应中断,响应超时,源码如下:

public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable { public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); return tryAcquireShared(arg) >= 0 || doAcquireSharedNanos(arg, nanosTimeout); } private boolean doAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException { // 如果超时时间小于等于0,则直接超时,返回false if (nanosTimeout <= 0L) return false; // 计算超时截止时间点(当前时间+超时时间) final long deadline = System.nanoTime() + nanosTimeout; // 封装节点并保存队列 final Node node = addWaiter(Node.SHARED); boolean failed = true; try { for (;;) {// 自旋 final Node p = node.predecessor(); if (p == head) { int r = tryAcquireShared(arg); if (r >= 0) { setHeadAndPropagate(node, r); p.next = null; // help GC failed = false; return true; } } // 计算剩余的超时时间 nanosTimeout = deadline - System.nanoTime(); // 如果剩余超时时间小于等于0,直接超时,返回false if (nanosTimeout <= 0L) return false; // 将前置节点置为SIGNAL,然后校验剩余超时时间,如果不足spinForTimeoutThreshold,则进入快速自旋,否则执行阻塞 if (shouldParkAfterFailedAcquire(p, node) && nanosTimeout > spinForTimeoutThreshold) LockSupport.parkNanos(this, nanosTimeout); // 再次响应中断 if (Thread.interrupted()) throw new InterruptedException(); } } finally { if (failed) cancelAcquire(node); } } }

解析:基本雷同,可以参考共享式获取同步状态的方法和独享式响应中断超时的获取方法。

release(int)

该方法表示独享式释放同步状态,源码如下:

public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable { public final boolean release(int arg) { // 首先尝试独享式释放同步状态 if (tryRelease(arg)) { Node h = head;// 头节点 // 头节点存在且状态不为0,则唤醒其后继节点 if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } // 释放失败返回false return false; } }

解析:首先调用tryRelease来尝试独享式释放同步状态,如果成功,则根据头节点的状态来决定是否唤醒后继节点,
头节点为0则不唤醒。唤醒操作通过调用unparkSuccessor方法来实现,具体逻辑之前已有描述,这里总结一下:
其实就是唤醒头节点之后的首个未被取消的节点线程,这个线程可能是独享式的也可能是共享式的。

tryRelease源码:

public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable { protected boolean tryRelease(int arg) { throw new UnsupportedOperationException(); } }

解析:tryRelease方法是一个模板方法,同样需要子类来实现。

releaseShared(int)

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

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