ReentrantLock与synchronized齐名的经典java锁,十分常用。
ReentrantLock本身没有直接实现锁,核心逻辑都交由AQS框架完成,内部核心类Sync即直接继承自AbstractQueuedSynchronizer类,
非公平锁模式:
公平锁模式:
对比两种模式可发现非公平模式下,一旦锁空闲了下来,新到来的线程可能会抢在等待队列中线程前面拿到锁,形成“插队”拿锁,还是直接插在了所有线程前面,但等待队列中的线程没有插队的机会,抱怨也没用,仍然是老老实实的按照顺序排队。
private final Sync sync;
ReentrantLock内部只有一个成员变量Sync,作为一个核心内部类,绝大部分方法都直接依赖这个类实现
ReentrantLock内部共3个内部类,其中Sync是一个抽象方法类,继承自AbstractQueuedSynchronizer,类NonFairSync与FairSync均继承自Sync
类Sync关键方法有3个 分别是lock、nonfairTryAcquire、tryRelease,其中lock是抽象方法,放下面介绍,先看nonfairTryAcquire
nonfairTryAcquire如期单词意义,是用来获取同步信号量的,并且是非公平式的,也就是说排队的线程获取顺序不是严格的先到先得,而是谁抢到就是谁的
//尝试获取释放状态
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
//不是当前线程则抛出异常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
//信号量恢复0代表持有当前锁的所有线程都已经释放完毕
if (c == 0) {
free = true;
//执行线程设置null
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
//非公平式尝试获取同步状态
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()) {
//锁已经被加锁过至少一次 并且加锁的是当前线程则信号量直接加acquires
int nextc = c + acquires;
//和小于0表明锁重入次数已经超过上限
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
NonfairSync类负责非公平锁 ,成员函数也很简单 仅有lock与tryAcquire两个,tryAcquire直接调用父类Sync的nonfairTryAcquire方法(这里吐槽下, nonfairTryAcquire感觉本来就应该放到NonfairSync类里面, 偏偏放Sync里面了,还绕了一个弯调用, 作者不知道咋想的 。。。)
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);
}
}
FairSync跟NonfairSync一样也只有两个成员函数lock 与tryAcquire
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
//不再快速尝试获取锁 而是直接排队获取
final void lock() {
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
//发现锁没人持有 并且等待队列是空的或者头结点线程就是当前线程 则cas尝试获取锁,
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;
}
}
//默认是非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
//指定是哪种锁
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
直接调用内部类的lock
public void lock() {
sync.lock();
}
直接调用内部类的unlock
public void unlock() {
sync.release(1);
}