可中断式获取锁
- 可响应中断式锁可调用方法lock.lockInterruptibly();该方法的底层会调用AQS的acqireInterruptibly方法;
acquireInterruptibly()方法:
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
doAcquireInterruptibly()方法:
- 如果当前线程的前驱节点为队头时,尝试获取同步状态
若获取成功则将队头节点出队,当前线程置为持有锁线程,并将队头指针指向当前线程所封装的节点,否则不断自旋直到获取成功或者线程被中断
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;
failed = false;
return;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
超时等待获取锁(tryAcquireNanos()方法)
- 调用lock.tryLock(timeout,TimeUnit)方式
- boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
- 超时等待锁的返回条件:
- 在指定时间内获取到锁
- 在指定时间内没有获取到锁
- 在指定时间内被中断
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
- 该方法调用AQS的tryAcquireNanos()方法:先判断是否被中断,然后尝试获取同步状态
如果成功则直接返会,否则进入到doAcquireNanos()方法:
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquire(arg) ||
doAcquireNanos(arg, nanosTimeout);
}
doAcquireNanos()方法:
private boolean doAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (nanosTimeout <= 0L)
return false;
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;
failed = false;
return true;
}
nanosTimeout = deadline - System.nanoTime();
if (nanosTimeout <= 0L)
return false;
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}