ReentrantLock是java1.5之后新增加的可重入锁,他也可以定时,公平。
在ReentrantLock中维护了一个Sync的对象,这就是我们重点需要分析的对象。
在ReentrantLock的lock中有如下代码
public void lock() {
sync.lock();
}
继续进入sync.lock()的方法
abstract void lock();
一个抽象方法肯定有自己的子类实现:
对于Sync的子类有两个:
NonfairSync(非公平锁)和FairSync(公平锁)
对于我们一般默认实现是非公平锁。在构造方法中也可以传入true or false,来构造是否是fair。
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
对于非公平锁的lock实现有如下代码
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
首先使用CAS设置当前状态为1,如果当前状态不为0,则执行acquire(1),如果当前状态为0设置状态为1,然后设置该锁当前拥有者为当前线程。
acquire()的代码如下
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
acquire是我们同步抽象队列中的代码,首先会进行tryAcquire(arg)目的是让线程重入锁,如果返回false就是不是同一个线程获取锁。继续执行acquireQueued,这就是其中的阻塞代码,具体是维护了一个队列,在代码中有一个死循环,当当前线程的结点和头结点相等并且尝试获取到了锁才会跳出。
对于公平锁的lock代码:
final void lock() {
acquire(1);
}
公平锁的具体是指后来线程只有插入后面的队列不能插队具体实现也是使用CAS。
unlock实现
public void unlock() {
sync.release(1);
}
继续跟进
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
在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;
}
首先把当前状态减去1,判断当前线程是不是拥有该把锁,如果该线程没有拥有该把锁抛出监视异常。如果当前状态都减为0了,设置该锁拥有者为Null,返回true。否则返回false。