平时加锁使用的 reentrantLock.lock()
方法, 默认是不可打断模式,即便 park 状态的线程被打断了,它也不会立即响应,它仍旧在 AQS 中运行着,直到拿到锁,再自己中断自己。
private final boolean parkAndCheckInterrupt() {LockSupport.park(this); // 线程停在了这里。// 获取当前线程是否被打断了,并且清空打断标记。return Thread.interrupted();
}
假设 T1 处于 park 状态,但被 T2 拿到了 T1的线程对象,调用 t1.interrupt()
方法,将 t1 从打断中给唤醒了。parkAndCheckInterrupt() 返回 true。
final boolean acquireQueued(final Node node, int arg) {// 拿锁失败?默认是。boolean failed = true;try {boolean interrupted = false;for (;;) // 如果获得不了锁,T1 依旧会进入 park。final Node p = node.predecessor();if (p == head && tryAcquire(arg)) {setHead(node); p.next = null; failed = false;// T1 只有拿到锁时,才能跳出这个死循环。// 返回 打断标记,true。return interrupted;}if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())// 被打断的 T1 执行到这里。interrupted = true;// 死循环,回到上面去重新执行。}} finally {if (failed)cancelAcquire(node);}
}
如果 T1 被打断后,拿到了锁,它返回到哪里了呢
public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // acquireQueued() 返回结果true。// 执行这个方法。selfInterrupt();
}static void selfInterrupt() {// T1自己重新产生一次中断。Thread.currentThread().interrupt();
}
调用 reentrantLock.lockInterruptibly()
那就是可打断的。
public void lockInterruptibly() throws InterruptedException {// 调用 AQS 的 acquireInterruptibly(1) 方法。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 GCfailed = false;return;}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())// park 的线程被打断后,直接抛异常。throw new InterruptedException();}} finally {if (failed)cancelAcquire(node);}
}
reentrantLock.lock()
加锁,线程是不可被打断的,因为即便 T1被打断了,它拿不到锁,从循环里出不来,依旧又会 park。reentrantLock.lockInterruptibly()
加锁,线程是能可被打断的,park 的线程一旦被打断,直接抛异常。本文发布于:2024-01-27 21:16:33,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/17063613952687.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |