ReentrantLock
是可重入的独占锁,同时只能有一个线程可以获取该锁,其他获取该锁的线程会被阻塞而被放入该锁的AQS阻塞队列里面。
根据参数来决定其内部是一个公平锁还是非公平锁。
默认非公平锁。
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
Sync
类直接继承自AQS,它的子类NonfairSync
、FairSync
分别实现了获取锁的非公平与公平策略。
abstract static class Sync extends AbstractQueuedSynchronizer {}
static final class NonfairSync extends Sync {}
static final class FairSync extends Sync {}
非公平锁的实现
非公平:先尝试获取锁的线程并不一定比后尝试获取锁的线程优先获取锁。
获取锁: void lock()
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
1、设置state的状态值为1 compareAndSetState(0, 1)
AQS的state状态值表示线程获取锁的可重入次数,默认为0表示当前锁没有被任何线程持有,当一个线程第一次获取该锁时会尝试使用CAS设置state的值为1,在该线程没有释放锁的情况下第二次获取该锁后,状态值被设置为2,这就是可重入次数。
2、如果CAS成功则当前线程获取了该锁,然后记录该锁的持有者为当前线程setExclusiveOwnerThread(Thread.currentThread())
。
3、如果CAS失败,会调用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;
}
执行nonfairTryAcquire
如果返回true,当前线程获取了该锁;
如果返回false,则其会被放入AQS阻塞队列acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
非公平锁的体现
明明是线程A先请求获取该锁,但线程B在获取锁前并没有查看AQS队列里面是否有比自己更早请求该锁的线程,而是使用了抢夺策略。
公平锁的实现
公平锁的tryAcquire
与非公平的类似:
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;
}
不同之处在于在设置CAS前添加了hasQueuedPredecessors()
,该方法是实现公平性的核心代码:
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());
}
h == t
:队列为空
s = h.next
:s为队列的第一个元素
h != t && s == null
:有一个元素将要作为AQS的第一个节点入队列
h != t && s != null && s.thread != Thread.currentThread()
:队列里面的第一个元素不是当前线程