目录
前言
ReentrantLock
是可重入的互斥锁,虽然具有与synchronized
相同功能,但是比synchronized更加灵活。
源码解析
ReentrantLock核心应用的是AQS(AbstractQueuedSynchronizer)。通过类图可以看出,ReentrantLock 实现了Lock接口,从而控制锁的获取和释放等操作。
其中比较重要的方法有 lock,tryLock 和tryrelease.
lock
@ReservedStackAccess
final void lock() {
if (!initialTryLock())
acquire(1);
}
/**
* Acquires only if reentrant or queue is empty.
*/
final boolean initialTryLock() {
Thread current = Thread.currentThread();
int c = getState();
//先尝试去获取锁,获取锁则返回成功
if (c == 0) {
if (!hasQueuedThreads() && compareAndSetState(0, 1)) {
setExclusiveOwnerThread(current);
return true;
}
//查看锁是不是被当前线程所占有,占有则state+1,返回true
} else if (getExclusiveOwnerThread() == current) {
if (++c < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(c);
return true;
}
return false;
}
这里acquire是调用父类的acquire方法,这其实是一个钩子方法,FairSync中重写了tryAcquire方法
public final void acquire(int arg) {
if (!tryAcquire(arg))
acquire(null, arg, false, false, false, 0L);
}
/**
* Acquires only if thread is first waiter or empty
*/
protected final boolean tryAcquire(int acquires) {
if (getState() == 0 && !hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
其中hasQueuedPredecessors()方法判断当前线程是否是队列第一个等待线程或者不存在等待队列
public final boolean hasQueuedPredecessors() {
Thread first = null; Node h, s;
if ((h = head) != null && ((s = h.next) == null ||
(first = s.waiter) == null ||
s.prev == null))
first = getFirstQueuedThread(); // retry via getFirstQueuedThread
return first != null && first != Thread.currentThread();
}
/**
* Returns the first (longest-waiting) thread in the queue, or
* {@code null} if no threads are currently queued.
*
* <p>In this implementation, this operation normally returns in
* constant time, but may iterate upon contention if other threads are
* concurrently modifying the queue.
*
* @return the first (longest-waiting) thread in the queue, or
* {@code null} if no threads are currently queued
*/
public final Thread getFirstQueuedThread() {
Thread first = null, w; Node h, s;
if ((h = head) != null && ((s = h.next) == null ||
(first = s.waiter) == null ||
s.prev == null)) {
// traverse from tail on stale reads
for (Node p = tail, q; p != null && (q = p.prev) != null; p = q)
if ((w = p.waiter) != null)
first = w;
}
return first;
}
ReentrantLock 有两个内部类NonfairSync和FairSync分别代表了公平锁和非公平锁,NonfairSync和fairSync的区别在于
NofairSync并不关心当前队列在等待队列中的位置
/**
* Acquire for non-reentrant cases after initialTryLock prescreen
*/
protected final boolean tryAcquire(int acquires) {
if (getState() == 0 && compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
}
tryLock
/**
* Performs non-fair tryLock.
*/
@ReservedStackAccess
final boolean tryLock() {
Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(current);
return true;
}
} else if (getExclusiveOwnerThread() == current) {
if (++c < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(c);
return true;
}
return false;
}
ReentrantLock 采取非公平锁的方式去实现tryLock,获取到锁就返回True,否则返回false,同一个线程没执行一次tryLock或者Lock 获取锁成功,state+1.
unlock
public void unlock() {
sync.release(1);
}
/**
* Releases in exclusive mode. Implemented by unblocking one or
* more threads if {@link #tryRelease} returns true.
* This method can be used to implement method {@link Lock#unlock}.
*
* @param arg the release argument. This value is conveyed to
* {@link #tryRelease} but is otherwise uninterpreted and
* can represent anything you like.
* @return the value returned from {@link #tryRelease}
*/
public final boolean release(int arg) {
if (tryRelease(arg)) {
signalNext(head);
return true;
}
return false;
}
@ReservedStackAccess
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (getExclusiveOwnerThread() != Thread.currentThread())
throw new IllegalMonitorStateException();
boolean free = (c == 0);
if (free)
setExclusiveOwnerThread(null);
setState(c);
return free;
}
当前线程占有锁时,每次release 都会使state-1,直到state=0,才释放锁。因此,每次,lock,或者tryLock以后都需要调用unlock来释放锁。
小结
reentrantLock实现了Lock接口,内部应用了AbstractQueuedSyncronizer的子类NonfairSync和FairSync来实现对锁的占用和释放。NonfairSync和FairSync的区别在于:FairSync在trylock时候会判断当前线程是否处于等待队列的队首位置,只有队首位置时才会去获取锁。此外,Lock方法并不区分公平锁还是非公平锁,同时使用非公平锁的方法去去获取锁。