在阅读本文前,需要对AQS有大概的了解
ReentrantLock,即重入锁,表示持有资源的锁的线程可对资源进行重复加锁,其支持公平和非公平两种模式,其默认使用非公平锁。
在ReentrantLock中,通过将加锁的操作委托给ReentrantLock$Sync来实现,Sync继承
AbstractQueuedSynchronizer,实现了tryRelease
,同时定义了nonfairTryAcquire
供其非公平实现NonfairSync调用。
ReentrantLock#lock
public void lock() {
sync.lock(); //委托给sync
}
我们先来看一下非公平锁
/**
* 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);
}
}
在lock时,如果对state
cas成功,则当前线程直接获取锁,并把自己设置位锁的持有者,否则调用acquire
, AQS 使用了模板方法
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
我们要关注的实际上是NonfairSync#tryAcquire
,可以看到,这里直接调用了Sync
提供的nonfairTryAcquire
/**
* 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) {
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;
}
在这里,同样如果state
为0,则尝试cas,并把自己设置为锁的持有者,若state
不为0,则检查自己是否为锁的持有者,若已持有,则state
加一,可以看到这里使得ReentrantLock可重入,下面我们看一下其公平实现
static final class FairSync extends Sync {
final void lock() {
acquire(1);
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
这里唯一的区别是在尝试对state进行CAS操作前加上了!hasQueuedPredecessors()
这个判断,这是用来判断是否有线程排队在当前线程之前,若有,则当前线程进入AQS同步队列。而在非公平实现中,当前线程可越过排队的线程直接尝试获取锁。
那么为什么默认要使用非公平锁呢,因为在非公平锁中,一个线程在释放了锁之后,再次竞争锁的时候,很可能继续获得锁,虽然有可能导致线程饥饿,但减少了上下文的切换,如果使用公平锁,则不会出现某一线程连续竞争到锁的情况,但会加大上下文切换,减小吞吐量
网友评论