AQS独占模式
1.公平锁
final void lock() {
acquire(1);
}
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
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;
}
}
1.先判断当前锁有没有占有(getState()),0没有占有
2.如有被占有,判断是不是占有的线程,是的话state+1;
3.如果不是,先判断LCH队列中有没有等待的node,如果有加入队尾,自旋等待唤醒。
4.如果LCH队列中没有,CAS尝试获
5.当前锁的线程释放锁之后,如果node节点的前置节点是head,会唤醒当前节点,去CAS获取锁,如果没成功一直,成功之后当前节点设置为head,如果释放之后继续唤醒后续
2.非公平锁
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
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;
}
区别:公平锁和非公平锁有两个地方不一样。
1.非公平锁在调用 lock 后,首先就会调用 CAS 进行一次抢锁,如果这个时候恰巧锁没有被占用,那么直接就获取到锁返回了
2.公平锁在抢占锁之前会先判断LCH队列中有没有等待的线程,有的话,加入到队尾,没有的话会CAS抢锁。非公平锁会直接抢锁,不判断队列信息。
相对来说,非公平锁会有更好的性能,因为它的吞吐量比较大。当然,非公平锁让获取锁的时间变得更加不确定,可能会导致在阻塞队列中的线程长期处于饥饿状态。