聊聊公平锁和非公平锁
Posted 魔法二少
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了聊聊公平锁和非公平锁相关的知识,希望对你有一定的参考价值。
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 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();
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires); //锁没有被占用或锁可重入则返回true
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) { //锁没有被占用
if (compareAndSetState(0, acquires)) { //注释3,执行cas
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
//已获得锁的线程就是当前线程【getExclusiveOwnerThread()获取当前占用锁的线程】,则重入(ReentrantLock是可重入锁)
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
}
公平锁:
//公平锁
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
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
//已获得锁的线程就是当前线程【getExclusiveOwnerThread()获取占用锁的线程】,则重入拿锁(ReentrantLock是可重入锁)
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
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; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
- ReentrantLock、Lock、FairSync、NonfairSync、Sync、AbstractQueuedSynchronizer之间的关系
ReentrantLock继承Lock,并拥有内部类FairSync、NonfairSync、Sync;FairSync、NonfairSync继承Sync;Sync继承AbstractQueuedSynchronizer之间的关系
以上是关于聊聊公平锁和非公平锁的主要内容,如果未能解决你的问题,请参考以下文章