ReentrantLock源码解读

RentrantLock总览

ReentrantLock是一个独占式的锁,支持重入.里面实现了公平锁与非公平锁;

其中ReentrantLock支持可公平锁与非公平锁,最顶层的父类是AQS.获取锁阻塞释放全部都是通过AQS来实现.接下来详细说明这些是怎么实现的.

Sync

继承自AQS

abstract void lock();

抽象方法,让子类也就是两个公平和非公平类来实现.

boolean nonfairTryAcquire(int acquires) ;

此为尝试获取非公平锁,非公平锁的实现就是首先CAS替换看自己是否能够获得锁,如果能够获得,则设置为拥有锁,如果不行,返回false;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
abstract static class Sync extends AbstractQueuedSynchronizer {
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;
}
}

boolean tryRelease(int releases)

释放掉指定的资源.如果当前线程没有拥有锁,则抛出异常.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
abstract static class Sync extends AbstractQueuedSynchronizer {
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);//设置状态,状态为0,表示没有线程获得锁
return free;
}
}

boolean isHeldExclusively()

表明当前线程是否是独占锁

1
2
3
4
5
protected final boolean isHeldExclusively() {
// While we must in general read state before owner,
// we don't need to do so to check if current thread is owner
return getExclusiveOwnerThread() == Thread.currentThread();
}

公平锁

ReentrantLock实现了两种锁,一种是非公平的,一种是公平的.两个的区别在于公平锁总是按照先来就先获得锁,非公平锁是谁抢到就算谁的.接下来看公平锁的实现:

lock

锁主要是通过acquire()实现锁住,acquire(1)方法是AQS中定义好的方法,acquire首先会调用自己所实现的tryacquire()方法,如果不成功则加入队列中,成功就直接获取到锁.

1
2
3
4
5
6
7
8
final void lock() {
acquire(1);
}
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}

这个方法如果有不了解,可以先去看我另一篇文章AQS详解

boolean tryAcquire(int acquires)

首先判断锁状态是否为0,如果为0,在判断阻塞队列中是否有前驱,如果没有前驱则设置此线程为拥有锁的线程.如果状态不为0,查看是否是自己拥有锁,如果不是返回false;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static final class FairSync extends Sync {
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的方法实现的.其实也就是用AQS定义好的框架来进行实现.这里就不一一说明了.有兴趣可以自己去看看源码