有了AQS的基础,可以了解ReentrantLock的原理。 相关文章
ReentrantLock简介
ReentrantLock支持公平、非公平方式获取互斥锁锁。
- 公平锁(Fair):加锁前检查是否有排队等待的线程,优先排队等待的线程,先来先得
- 非公平锁(NonFair):加锁时不考虑排队等待问题,直接尝试获取锁,获取不到自动到队尾等待
ReentrantLock正如其名,是可重入的
可重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,但不受影响。
ReentrantLock底层使用了AQS工具类。ReentrantLock和AQS的关系如下:

ReentrantLock的内部类Sync继承自AQS,还有FairSync、NonFairSync继承于Sync类。
ReentrantLock源码
ReentrantLock内部包含一个Sync实例,核心的lock、unlock操作交给Sync实例负责。 Sync实例可以是NonFairSync或者FairSync。
public class ReentrantLock implements Lock, java.io.Serializable {
/** Synchronizer providing all implementation mechanics */
private final Sync sync;
public void lock() {
sync.lock();
}
public void unlock() {
sync.release(1);
}
ReentranLock.Sync
AbstractQueuedSynchronizer提供了tryXXX模板方法,供子类覆盖。Sync覆盖了tryRelease(),并且提供了nonfairTryAcquire()
abstract static class Sync extends AbstractQueuedSynchronizer {
abstract void lock();
/**
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
// 使用AQS.state字段保存
// 对于非公平锁,一旦发现锁可以占有,则当前线程抢占锁
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;
}
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;
}
回想AQS的属性
private transient volatile Node head;
private transient volatile Node tail;
/**
* The synchronization state.
*/
private volatile int state;
子类使用state字段存储同步状态。这里使用state记录线程获取锁的次数。
ReentranLock是互斥锁,每次获取的许可数都是1。释放锁则可以一次释放多个许可。
NonfairSync
static final class NonfairSync extends Sync {
final void lock() {
// fast-path
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
FairSync
static final class FairSync extends Sync {
final void lock() {
acquire(1);
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
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;
}
}
ReentrantLock实践
一定要释放锁。通常在finally释放。
ReentrantLock lock=new ReentrantLock();
try{
lock.tryLock();
// do something
}finally{
lock.unlock();
}
公平锁 vs 非公平锁
公平锁按照请求资源的先后顺序获取锁。会导致频繁切换线程上下文。吞吐量比非公平锁低。 非公平锁获取锁的时候不会检查等待队列。可能发生一个线程反复获取锁,导致其他线程发生“饥饿”。
ReentrantLock vs synchronized
ReentrantLock支持公平锁、非公平锁模式,synchronized是非公平锁。 ReentrantLock和synchronized都是可重入锁。 ReentrantLock底层使用AQS实现,synchronized使用java的隐式锁实现。 ReentrantLock支持超时等待(tryLock)。 在java6之前,synchronized性能要比ReentrantLock低。
ReentrantLock和Condition
Condition是线程间通信的方式。Condition要绑定Lock。ReentrantLock提供了Condition支持。具体参见
小结
ReentrantLock使用了AQS的互斥锁能力。使用state变量记录线程获取锁的次数。