昨天不是放假嘛,端午然后广州这边疫情+下雨,二少就找了些AQS的资料看看,没错,就是肝!在广州的小伙伴要保护好自己哈,反正听党的话,不要乱跑就是了,哈哈~
AQS中公平锁和非公平锁怎么实现的?
如上图所示,公平锁和非公平锁的代码主要有两处地方有区别:
- 公平锁调用lock()方法获取锁时,直接抢占锁【acquire(1),见注释1】, 非公平锁调用lock()方法获取锁时,先执行cas获取锁,获取失败后再抢占锁【acquire(1),见注释2】;
- 调用acquire(1)抢占锁时,若锁没有被占用(state=0)
- 非公平锁则直接执行cas代码尝试获取锁(见注释3);
- 公平锁则先检查AQS队列,若AQS队列为空或AQS头节点的后继节点是当前节点(见注释4的hasQueuedPredecessors()方法),则再执行cas代码尝试获取锁(见注释5);
公平锁:
//公平锁
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);//注释1,调用lock()后直接抢占锁
}
//非公平锁和公平锁都会执行该方法
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
/**
* 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() && //hasQueuedPredecessors返回false后可继续执行compareAndSetState=cas
compareAndSetState(0, acquires)) { //注释5,cas方法
setExclusiveOwnerThread(current);//设置占用锁的线程为当前线程,并返回true
return true;//返回true后拿锁成功,即lock()拿锁成功
}
}
else if (current == getExclusiveOwnerThread()) {
//已获得锁的线程就是当前线程【getExclusiveOwnerThread()获取占用锁的线程】,则重入拿锁(ReentrantLock是可重入锁)
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);//重新设置同步转态state
return true;
}
return false;
}
//注释4:若AQS队列为空或AQS头节点的后继节点是当前节点,返回false
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; //AQS队列的尾结点, Read fields in reverse initialization order
Node h = head; //AQS队列的头结点
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
非公平锁:
//非公平锁
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)) //注释2,调用lock()后先执行cas试图获取锁
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1); //获取失败后再抢占锁
}
//非公平锁和公平锁都会执行该方法
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
//锁没有被占用或锁可重入则返回true
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) { //锁没有被占用
if (compareAndSetState(0, acquires)) { //注释3,执行cas
setExclusiveOwnerThread(current); //设置占用锁的线程为当前线程,并返回true
return true;//返回true后拿锁成功,即lock()拿锁成功
}
}
else if (current == getExclusiveOwnerThread()) {
//已获得锁的线程就是当前线程【getExclusiveOwnerThread()获取当前占用锁的线程】,则重入(ReentrantLock是可重入锁)
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);//重新设置同步转态state
return true;
}
return false;
}
}
}
- ReentrantLock、Lock、FairSync、NonfairSync、Sync、AbstractQueuedSynchronizer之间的关系
ReentrantLock实现Lock,并拥有内部类FairSync、NonfairSync、Sync;FairSync、NonfairSync继承Sync,同时Sync继承AbstractQueuedSynchronizer
OK,如果文章哪里有错误或不足,欢迎各位留言。
创作不易,各位的「三连」是二少创作的最大动力!我们下期见!