问题1:一个线程用lock方法申请锁而被阻塞后,调用线程的interput方法,会发生什么情况,能中断锁的获取吗?
问题2:什么是CLH算法,RenntrantLock针对CLH算法做了哪些变化。
问题3:Node.CANCEL状态的节点在什么时候会删除。
1、ReentrantLock#lock 方法详解
=========================
如下摘录自 ReentrantLock.NonFairSync
final void lock() {
if (compareAndSetState(0, 1)) // @1
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1); // @2
}
代码@1 首先线程请求锁时,第一步,直接通过锁的状态 state, 如果 state 为0,通过 CAS 尝试去获取锁,如果获取,直接返回,这里就是所谓的不公平,先抢占,然后再尝试排队。如果当前锁被占用,则尝试申请锁, 进入代码 @2;
继续查看 acquire(1)方法,该方法存在于 AbstractQueuedSynchronizer 类,该类是 java.util.concurent.locks 锁的队列机制实现类,基于CLH 算法的变体的基本思想。,附上 AbstractQueuedSynchronizer 的 acquire 方法源码。
/**
-
Acquires in exclusive mode, ignoring interrupts. Implemented
-
by invoking at least once {@link #tryAcquire},
-
returning on success. Otherwise the thread is queued, possibly
-
repeatedly blocking and unblocking, invoking {@link
-
#tryAcquire} until success. This method can be used
-
to implement method {@link Lock#lock}.
-
@param arg the acquire argument. This value is conveyed to
-
{@link #tryAcquire} but is otherwise uninterpreted and
-
can represent anything you like.
*/
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
//那我们先进入到 tryAcquire(arg)方法,查看获取锁的逻辑,该方法不阻塞。
protected boolean tryAcquire(int arg) { // 说明,该方法在具体的子类中实现。
throw new UnsupportedOperationException();
}
我们一路跟踪进来,发现尝试获取锁的代码在 ReentrantLock内部类 Sync 汇总,Sync 是 NonFairSync 和 FairSync 的父类。
/**
-
Performs non-fair tryLock. tryAcquire is
-
implemented in subclasses, but both need nonfair
-
try for trylock method.
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) { // @1
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) { // @2
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error(“Maximum lock count exceeded”);
setState(nextc);
return true;
}
return false;
}
该方法,尝试获取锁,如果成功获取锁,则返回true,否则,返回false;
重点关注 代码@1, 再次查看 锁的 state,该字段,表示该锁被占用的次数,如果为0,表示没有线程持有该锁,如果 大于1,表示同一个线程,多次请求锁;也就是可重入锁的实现原理。
代码@2:进一步说明可重入锁的实现机制。再次回到上文提到的 AbstractQueuedSynchronizer的 acquire(arg)方法:
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)