ReentrantLock的lockInterruptibly、
2022-01-16 本文已影响0人
virtual灬zzZ
lockInterruptibly
能响应interrupt中断,调用就是会有catch块,catch InterruptedException并处理。
lock
不能响应interrupt中断,interrupt对它没影响,它会继续往下执行程序。
tryLock
尝试获取锁,获取不到直接放弃
tryLock(timeout,timeUnit)
尝试获取锁,在指定时间内拿不到直接放弃
区别::
lock:
可以看到 排队阻塞的方法里头,lock是不会抛出异常的,只是设置interrupted这个变量返回,但这个变量无论true、false,对于获取锁功能没有任何作用, parkAndCheckInterrupt方法里面 ,被唤醒之后执行 Thread.interrupted()返回该线程是否被打断并清除它的中断标志,interrupted 变量是true的话,回到外面执行selfInterrupt()方法,只是还原该线程的中断标志,原因是 不能改变用户对于该线程的 操作,用户想改变它的中断标志,aqs不能擅自改变用户操作。
public void lock() {
sync.lock();
}
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
lockInterruptibly:(有抛出 InterruptedException )
对于lockInterruptibly,可见是会抛出InterruptedException的,位置在一进来如果判断线程的中断标志是true,立马抛InterruptedException,跳到外面的catch块中。
还有就是在双向队列中排队,被唤醒继续执行,发现线程中断标志是true,立马抛InterruptedException,也是去到catch块中。
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
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())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
tryLock()
仅仅进行尝试获取锁,直接放回成功还是失败。
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
tryLock(timeout,timeUnit)
还是一开始如果检测到中断标志,直接抛异常不执行下去,如果排队过程超时,放回false,如果排队被唤醒判断是被中断了,直接抛异常。
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquire(arg) ||
doAcquireNanos(arg, nanosTimeout);
}
private boolean doAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (nanosTimeout <= 0L)
return false;
//1. 根据超时时间和当前时间计算出截止时间
final long deadline = System.nanoTime() + nanosTimeout;
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (; ; ) {
final Node p = node.predecessor();
//2. 当前线程获得锁出队列
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return true;
}
// 3.1 重新计算超时时间
nanosTimeout = deadline - System.nanoTime();
// 3.2 已经超时返回false
if (nanosTimeout <= 0L)
return false;
// 3.3 线程阻塞等待
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
// 3.4 线程被中断抛出被中断异常
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
流程图: