- ReentrantLock.lockInterruptibly允许在等待时由其它线程调用等待线程的Thread.interrupt方法来中断等待线程的等待而直接返回,这时不用获取锁,而会抛出一个InterruptedException。
- ReentrantLock.lock方法不允许Thread.interrupt中断,即使检测到Thread.isInterrupted,一样会继续尝试获取锁,失败则继续休眠。只是在最后获取锁成功后再把当前线程置为interrupted状态。
具体实现如下:
1.lock
Lock在第一次获取锁失败后会走:
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) //中断当前线程 selfInterrupt(); }
addWaiter封装Node节点插入到队列尾部,acquireQueued负责队列的挂起、出队、是否中断
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; } //shouldParkAfterFailedAcquire:判断线程可否安全挂起 //parkAndCheckInterrupt:挂起线程并返回当时中断标识Thread.interrupted() if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) //当parkAndCheckInterrupt返回中断标识为true时修改interrupted interrupted = true; } } finally { if (failed) cancelAcquire(node); } }
2. lockInterruptibly
lockInterruptibly会直接走下面程序
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; // help GC failed = false; //这里没有中断标识 //lock和lockInterruptibly区别就是对中断的处理方式 return; } //shouldParkAfterFailedAcquire:判断线程可否安全挂起 //parkAndCheckInterrupt:挂起线程并返回当时中断标识Thread.interrupted() if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) //当parkAndCheckInterrupt返回中断标识为true时立即抛出异常中断线程 throw new InterruptedException(); } } finally { if (failed) cancelAcquire(node); } }