继上一篇对公平锁的解析,这次来看下非公平锁又是怎么做的。
同样的,使用时都会调用到lock方法。
public void lock() {
sync.lock();
}
然后经由Sync的子类实现,调用到NonfairSync的lock方法。其中lock方法主要做的就是线程一进来就尝试用过CAS获取锁,如果成功则直接设置当前线程为获取到锁的线程,否则进入acquire方法。(注:公平锁再CAS获取锁时先需要判断获取锁的线程是否是队列内的第一个节点,也就是说对于公平锁而言后进入等待队列的线程肯定晚于先进入队列的线程得到锁)
/**
* Sync object for non-fair locks
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
然后会调用到AbstractQueuedSynchronizer的acquire方法。(注:公平锁也一样会调用到该方法)
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
与公平锁不同的是,tryAcquire的调用会传递到子类NonfairSync的tryAcquire方法上,最后调用到的是Sync的nonfairTryAcquire 方法。
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
//如果当前没有任何线程获取到锁
if (c == 0) {
//尝试CAS获取锁
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;
}
最后其余入队、阻塞、唤醒等操作与公平锁一样,再上篇中都已述说。