1 简介
根据线程获取锁的抢占机制,锁可以分为公平锁和非公平锁。
- 公平锁:获取锁的顺序按照线程请求锁的时间顺序决定,ji简单来说,早申请早获取到锁,晚申请晚获取到锁。
- 非公平锁:获取锁的顺序不一定按照请求锁的时间来决定,早申请不一定先得到锁。
2 实现
ReentrantLock
提供了公平锁与非公平锁的实现:
- 公平锁:ReentrantLock pairLock = new ReentrantLock(true);
- 非公平锁:ReentrantLock pairLock = new ReentrantLock(false);
没有公平性需求尽量使用非公平锁,公平锁会带来额外的性能开销。
3 原理
ReentrantLock
的公平锁和非公平锁最终都委托抽象同步队列 AQS
的 acquire()
来获取
//AbstractQueuedSynchronizer#acquire
public final void acquire(int arg) {
//抽象方法,实现类去实现该方法
if (!tryAcquire(arg) &&
//acquireQueued():多次尝试获取锁或者阻塞
//addWaiter():将线程结点加入到等待队列
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
//线程中断,调用`Thread.currentThread().interrupt()` 中断线程
selfInterrupt();
}
3.1 公平锁
//锁
final void lock() {
acquire(1);
}
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;
}
public final boolean hasQueuedPredecessors() {
Node t = tail;
Node h = head;
Node s;
//1.如果该线程由前驱结点返回 true,
//2.否则,如果当前 AQS 队列为空或者当前线程结点是第一个结点返回 false
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
3.2 非公平锁
//锁
final void lock() {
//lock 时候,随机抢占,直接进行加锁操作,而公平锁是直接调用 acquire(1)
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
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;
}