f双方都
在重入锁(ReentrantLock)中,有两个相似的方法,一个是lock,一个是lockInterruptably,之前没有细看,之前我一直用的是lock,不过最近再看公司的代码时,发现有人竟然用的是后者,于是我就好奇了,特么的到底哪里不一样,于是跟了下源码,特此记录一下。(ReentrantLock使用aqs实现的,最好先看懂aqs再来搞重入锁)。
再lock中,最终调用的是:java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(int)方法,
public final void acquire(int arg) { if (!tryAcquire(arg) &&//尝试获得锁,失败时返回false acquireQueued(addWaiter(Node.EXCLUSIVE), arg))//入队列,然后挂起线程,我们重点看一下这个方法 selfInterrupt(); }
挂起线程的方法
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) &&//判断是否应该park parkAndCheckInterrupt())//park当前的线程 interrupted = true; } } finally { if (failed) cancelAcquire(node); } }
挂起当前的线程的代码,在挂起一定时间后,返回的是当前的线程是否有interruptted的状态
private final boolean parkAndCheckInterrupt() { LockSupport.park(this); return Thread.interrupted(); }
从上面的代码可以看出,如果某个线程在等待锁的时候别interrupt了,那么在获得锁之后,就会在acquireQueued方法中返回true,然后我们回到acquire中,在上面的parkAndCheckInterrupt方法返回true之后(也就是当前的线程是被interrupt了),就会进入selfInterrupt方法,里面很简单,就一句
private static void selfInterrupt() { Thread.currentThread().interrupt();//自己调用interrupt方法,但是这样不会有任何的作用,也就是直接忽略了在等待的时候别的线程对当前线程的interrupt操作。 }
从上面的分析中,我们得到结论,lock方法中会忽略在当前线程被park的时候其他线程堆当前线程的interrupt方法,不会有任何操作。
我们再分析一下,lockInterruptably方法,他在尝试获取锁失败后,会进入这个方法:
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())//从上面的代码分析中,我们已经知道了,当当前的线程在park之后,如果当前的线程被interrupt之后,就会返回true,那么就会进入if,即抛出一个interruptedException。 throw new InterruptedException(); } } finally { if (failed) cancelAcquire(node); } }
从上面的分析中,我们便知道了,lockInterruptably,会在park之后,抛出一个异常,这就是区别
so easy!!!