AQS之ReentrantLock分析 (四)
原创
©著作权归作者所有:来自51CTO博客作者959_1x的原创作品,请联系作者获取转载授权,否则将追究法律责任
文章目录
- 1.AQS 子类
- 2.ReentrantLock 简介
- 2.1 Sync
- 2.2 state
- 2.3 exclusiveOwnerThread
- 3.1 非公平锁 NofairSync
- 3.2 公平锁 FairSync
1.AQS 子类

- Semphore: 共享锁案例
- ReentrantLock: 排他锁案例
- ReentrantReadWriteLock: 共享锁和排它锁案例
- ThreadPoolExecutor
- CountDownLatch: 共享锁案例

2.ReentrantLock 简介

ReentrantLock 为可重入锁。
2.1 Sync
和Semaphore相似,ReentrantLock也是通过一个抽象类Sync继承了AbstractQueuedSynchronizer,Sync又有两个子类FairSync和UnFairSync,分别代表公平锁和非公平锁。

ReentrantLock有两个构造方法,public ReentrantLock(boolean fair)指定公平策略,public ReentrantLock()无参构造器则默认使用非公平锁。

2.2 state
state在不同的AQS里有不同的含义,比如Semaphore
的permits
数量和CountDownLatch
的计数值count
,在ReentrantLock里可以理解为锁的重入次数。
在ReentrantLock里,state固定初始化为0,代表无锁状态,线程获得锁计数修改为1,后续该线程每次重入都会使计数加1,离开锁时减1,直到state=0重新加入无锁状态,其他线程可以竞争获得锁。
AbstractQueuedSynchronizer.state

2.3 exclusiveOwnerThread
exclusiveOwnerThread
字段是由AbstractQueuedSynchronizer
的父类AbstractOwnableSynchronizer
提供的一个字段,可以用于代表当前获取资源的线程。


3.获取锁
public static void main(String[] args){
ReentrantLock lock = new ReentrantLock();
// lock.lock();
//
// lock.unlock();
}

- FairSync: 公平锁
- NofairSync: 非公平锁
3.1 非公平锁 NofairSync
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}

- tryAcquire(): 尝试获取资源
- addWaiter(): 添加Node到等待队列中, 将没有获取到锁资源的线程甩到队列的尾部。
- acquireQueued(): 将已经在队列中的node尝试去获取锁否则挂起。
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
//无锁状态,CAS获取锁
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)获取当前state,根据是否有锁状态分别处理
(2)无锁状态:CAS修改state拿锁,修改成功则说明获取锁成功,否则说明有其他线程竞争到了锁,反悔失败
(3)有锁状态:判断持锁线程是否是当前线程,是则进行重入,state加1,否则返回失败
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
如果没有获得资源的话, 会添加到一个CLH队列中
3.2 公平锁 FairSync

protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
//没有前驱节点才能通过CAS拿锁
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;
}
公平锁的特性就是先到先得,因此和非公平锁的差异就是无锁状态下只有队列里没有当前线程的前驱节点时才能去竞争锁。
4.释放锁


protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
只需要对state进入减操作,当state=0了,说明锁完全释放,这时候才返回成功并且将setExclusiveOwnerThread置为null,说明无线程持有锁
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread);
}
通过判断Node的waitStatus进行释放锁的操作, 如果waitStatus<0的话设置为等待节点
