ReentrantLock源码简析
概念
ReentrantLock,可重入锁。在多线程中,可以通过加锁保证线程安全。
加锁和解锁
- 加锁:
public void lock() {
sync.lock();
}
- 解锁
public void unlock() {
sync.release(1);
}
内部类Sync继承AQS(AbstractQueuedSynchronizer),因此可以维护状态变量state,通过acquire()获取state、release()释放state。后文会涉及。
构造方法
- 无参构造方法
默认使用非公平锁。
/**
* 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();
}
Sync类
Sync类是一个继承AQS的内部静态抽象类。
Sync继承AQS,因此也可以维护状态变量state,通过acquire()获取state、release()释放state。
公平锁FairSync和非公平锁NonfairSync,都继承Sync类,并且重写了Sync类中的抽象方法Lock()。
其中的nonfairTryAcquire()方法,是ReentrantLock最核心的实现。
如果状态变量state为0,说明目前还没有其他线程加锁,当前线程可以进行加锁,通过CAS将状态变量state加1。
并且当前线程会获得锁。
如果状态变量state不为0,且获取锁的是当前线程,则将state加1。
/**
* Base of synchronization control for this lock. Subclassed
* into fair and nonfair versions below. Uses AQS state to
* represent the number of holds on the lock.
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
/**
* Performs {@link Lock#lock}. The main reason for subclassing
* is to allow fast path for nonfair version.
*/
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();
//如果状态变量state为0,说明目前还没有其他线程加锁,当前线程可以进行加锁,通过CAS将状态变量state加1。
//并且当前线程会获得锁。
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
//如果状态变量state不为0,且获取锁的是当前线程,则将state加1。
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
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
//如果state为0,则说明已经释放锁,当前没有线程获得锁。
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
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();
}
final ConditionObject newCondition() {
return new ConditionObject();
}
// Methods relayed from outer class
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
final boolean isLocked() {
return getState() != 0;
}
/**
* Reconstitutes the instance from a stream (that is, deserializes it).
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
非公平锁和公平锁
非公平锁和公平锁,都重写了tryAcquire()。而acquire()是AQS中的方法。
- 非公平锁:
非公平锁的调用过程: lock()---> acquire(1) ---> tryAcquire(1) ---> nonfairTryAcquire(1)
/**
* Sync object for non-fair locks
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
- 公平锁:
主要流程:lock()--->acquire(1)--->tryAcquire(1)---> hasQueuedPredecessors()
公平锁和非公平锁的主要区别是:
公平锁,会去判断“当前线程”是不是AQS的线程等待队列(CLH队列)中的第一个线程,并对state进行CAS操作。
这个区别在hasQueuedPredecessors()方法中体现。
/**
* Sync object for fair locks
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
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();
//如果当前状态变量为0(也就是没有线程获取到锁)
if (c == 0) {
//判断“当前线程”是不是AQS的线程等待队列(CLH队列)中的第一个线程,并对state进行CAS操作。
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和Synchronized的区别
- Synchronized是基于监视锁monitor实现的,当monitor为0时,线程能够获得锁,此时monitor加1。当有线程进行请求时,判断monitor是否为0,如果不为0,说明锁已经被其他线程拿到了。Synchronized是JVM级别的锁。
而ReentrantLock是基于AQS实现的,AQS是一个抽象队列容器。当有线程发起请求时,如果是公平锁,需要在队列中等待。如果是非公平锁,会插队。
- Synchronized可以是方法锁、对象锁。
而ReentrantLock可以在代码中灵活地加锁、解锁。但要注意,必须在finally中进行unlock()。