ReentrantLock锁用法可以参考JUC-ReentrantLock锁基础篇
AQS用法可以参考JUC-AQS原理篇
AQS源码解析可以参考JUC-AQS源码篇
AQS之Condition源码解析可以参考JUC-AQS的Condition之await和signal源码解析
建议阅读ReentrantLock锁源码时,先去阅读JUC-ReentrantLock锁基础篇,涉及到的AQS源码可以参考JUC-AQS源码篇
ReentrantLock内部有一个继承AbstractQueuedSynchronizer的静态抽象类Sync,NonfairSync和FairSync继承了Sync并实现了它的抽象方法lock()。
在ReentrantLock中,AQS有tryAcquire(int arg),tryRelease(int arg)两个方法需要子类来实现。而子类Sync只实现了tryRelease方法,tryAcquire由Sync的子类NonfairSync和FairSync来实现。而Sync自己也有一个抽象方法方法lock()需要它的子类来实现。
总的来说就是
Sync实现了AQS的抽象方法tryRelease。
NonfairSync实现了AQS的抽象方法tryAcquire和Sync的抽象方法lock
FairSync也实现了AQS的抽象方法tryAcquire和Sync的抽象方法lock
private final Sync sync;
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
由上面可以看出通过参数fair可以控制是创造一个公平的锁ReentrantLock还是一个非公平的锁ReentrantLock。什么是公平锁什么是非公平锁可以参考上面的JUC-ReentrantLock锁基础篇中的公平锁,非公平锁的讲解。
ReentrantLock加锁的方法调用大致过程是:
reentrantLock类的lock()调用—>Sync子类实现的lock()调用—>AQS类的acquire(1)调用—>Sync子类实现的tryAcquire(1)
ReentrantLock解锁的方法调用大致过程是:
reentrantLock类的unlock()调用—>AQS类的release(1)—>Sync类的tryRelease(1)
在ReentrantLock中AQS的成员变量state取值的含义:
我们知道ReentrantLock获取锁调用的入口方法是reentrantLock.lock()方法。
//此lock方法是ReentrantLock类里面的
public void lock() {
//如果是公平锁的话,sync.lock()方法调用的是FairSync类里面的lock方法。
//如果是非公平锁的话,sync.lock()方法调用的是NonfairSync类里面的lock方法。
sync.lock();
}
抽象类Sync的lock()抽象方法是由它的两个子类FairSync和NonfairSync来实现的。
而成员变量sync引用究竟是指向抽象类Sync的那个子类,则是根据ReentrantLock的构造函数决定的
//此lock方法是FairSync类里面的
final void lock() {
acquire(1);
}
lock()方法直接调用父类AQS(AbstractQueuedSynchronizer)里面的acquire方法。
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
acquire方法的作用就是通过调用tryAcquire方法判断能否获取锁,不能的话就将当前线程加入同步队列中并阻塞。
AQS里面的acquire方法会先调用tryAcquire方法判断能否获取锁,其他的方法,如acquireQueued,addWaiter,selfInterrupt都是属于AQS的内部方法,可以参考JUC-AQS源码篇进行阅读。而tryAcquire方法是由AQS的子类来进行实现的。
在公平锁的情况下,tryAcquire方法是由FairSync类来进行实现的。其源码如下:
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
//获取state值
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;
}
此方法返回true的话,代表获取了锁,返回false的话就代表获取锁失败。
大致逻辑就是
//此lock方法是NonfairSync类里面的
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
此方法是先调用compareAndSetState通过CAS的方法看能不能获取到锁,如果获取不到的话,就再调用父类AQS(AbstractQueuedSynchronizer)的acquire方法。从这就可以看出非公平性出来了,当前线程不管前面还有没有等着获取锁的线程,它先抢锁,抢到了就是它的了。
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
acquire方法的作用就是通过调用tryAcquire方法判断能否获取锁,不能的话就将当前线程加入同步队列中并阻塞。
AQS里面的acquire方法会先调用tryAcquire方法判断能否获取锁,其他的方法,如acquireQueued,addWaiter,selfInterrupt都是属于AQS的内部方法,可以参考JUC-AQS源码篇进行阅读。而tryAcquire方法是由AQS的子类来进行实现的。
在非公平锁的情况下,tryAcquire方法是由NonfairSync类来进行实现的。其源码如下:
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
NonfairSync的tryAcquire方法是直接调用了父类Sync的nonfairTryAcquire方法:
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
//获取state变量
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;
}
此方法返回true的话,代表获取了锁,返回false的话就代表获取锁失败。
大致逻辑就是
我们知道ReentrantLock释放锁调用的入口方法是reentrantLock.unlock()方法。
public void unlock() {
sync.release(1);
}
此方法直接调用AQS的release方法:
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
release方法通过调用tryRelease方法来尝试释放当前的锁,如果释放成功的话,就唤醒head节点的后继节点。tryRelease方法是由AQS的子类Sync类来实现的。
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
tryRelease方法的大致逻辑是: