您的位置:首页 > 编程语言 > Java开发

AQS(5):ReentrantLock

2016-04-04 11:53 429 查看
ReentrantLock在行为和语义上与synchronized类似,但是更具可扩展性。该锁是可重入的,并且有公平和非公平两种选项。在学习了AQS之后,理解ReentranLock就更容易了。我们知道,AQS已经提供了状态管理,阻塞,队列管理等功能。继承于它的同步工具类只需要实现诸如tryAcquire,tryRelease等基础方法就能实现锁的功能。自然,在ReentrantLock中也包含了Synchronizer对象。

该类中定义了一个静态抽象类Sync作为公平Sync和非公平Sync的基类,定义了公共的tryRelease方法。

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可以简单理解为如果大于0表示持有锁时重入次数,如果等于0则没有线程持有锁。因此简单的判断release后是否为0并重新设置state就可以了。该类中还定义了一个nonfairTryAcquire方法。

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;
}


该方法的思路仍然是通过state确定是否加锁成功。首先如果state=0,即无人持有锁,那么通过CAS更改state,注意,此处由于可能存在竞争,必须使用CAS而非普通的比较设置两段操作。如果当前线程已经持有锁,那么本次是重入,仅记录一下重入状态就可以了。

接下来是设计公平和非公平的Sync具体子类。我们先来看NonfairSync中的lock方法。

final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}


这就体现了非公平性,他会直接通过判断state强行尝试一次,而不是在队列中排队通过acquire来取得锁。我们整体描述一下非公平锁的lock流程。首先,根据state判断能否立即加锁成功,如果不能则调用acquire;在acquire过程中,调用tryAcquire,这个方法中又会判断一次state,如果又失败,就向同步队列添加一个节点.这种情况下只有当该节点前驱是头结点的时候才会尝试用tryAcquire取得锁,否则就被阻塞。可以看到,在这个过程中,非公平锁至少会两次尝试通过CAS更改state来取得锁。

在fairSync中的tryAcquire方法流程就不同了,由于考虑到公平性,不能只根据state就决定是否取得锁。该过程中,如果无人持有锁,那么判断他有没有前驱节点,如果没有,再让自己持有锁,这就是公平性的体现。

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;
}


该类中的其他方法基本都是对Sync中定义方法的调用,没有其他的新意,对ReentrantLock的解析就到这里了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 多线程