可中斷式獲取鎖
- 可響應中斷式鎖可調用方法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);
}
}