AcquireInterruptibly (int arg)
AQS provides acquire(int ARG) method for exclusive acquisition of synchronization state, but this method does not respond to interrupt. After the interrupt operation, the thread will still be in the CLH synchronization queue waiting to obtain synchronization state. To respond to interrupts, AQS provides the acquireInterruptibly(int ARG) method, which immediately throws InterruptedException if the current thread is interrupted while waiting to obtain the synchronization status.
// Template method, exclusive lock (synchronous state) response is interrupted
public final void acquireInterruptibly(int arg)
throws InterruptedException {
// Determine whether the interrupt is present
if (Thread.interrupted())
throw new InterruptedException();
if(! tryAcquire(arg)) doAcquireInterruptibly(arg); }Copy the code
private void doAcquireInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for(; ;) {final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
The only difference with acquireQueued is that an exception is thrown if it is broken
throw newInterruptedException(); }}finally {
if(failed) cancelAcquire(node); }}Copy the code
TryAcquireNanos (int arg,long timeout)
In addition to the above two methods, AQS provides an enhanced version of the method: tryAcquireNanos(int arg,long Nanos). This method is a further enhancement to the acquireInterruptibly method, which has timeout control in addition to responding to interrupts. That is, false is returned if the current thread did not acquire synchronization status within the specified time, and true is returned otherwise. As follows:
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquire(arg) ||
doAcquireNanos(arg, nanosTimeout);
}
Copy the code
private boolean doAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
// Return if nanosTimeout is less than 0
if (nanosTimeout <= 0L)
return false;
// By setting the current time + the set timeout = the timeout point
final long deadline = System.nanoTime() + nanosTimeout;
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for(; ;) {final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return true;
}
// Timeout point - Current time = remaining timeout
nanosTimeout = deadline - System.nanoTime();
// If the remaining timeout period is less than 0, the value is returned
if (nanosTimeout <= 0L)
return false;
// Wait nanosTimeout nanoseconds if there is no timeout
// Note: this thread returns directly from locksupport. parkNanos(this, nanosTimeout)
//LockSupport is a blocking and waking utility class provided by JUC
if (shouldParkAfterFailedAcquire(p, node) &&
// If nanosTimeout is larger than spinForTimeoutThreshold, it needs to sleep nanosTimeout
nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
// If nanosTimeout is less than or equal to spinForTimeoutThreshold, then it does not need to sleep and goes directly to fast spin
// Because spinForTimeoutThreshold is already short, sleeping for shorter timeouts may result in less accurate timeouts
// Thread state transitions take time
// Determine whether the thread has been interrupted
if (Thread.interrupted())
throw newInterruptedException(); }}finally {
if(failed) cancelAcquire(node); }}Copy the code
The difference with the exclusive access lock response interrupt is the calculation of the timeout after joining the synchronization queue