所谓的可重入就是一个线程获取到了锁之后,同一个线程还是想要再次的获取到这个锁,那么这个锁可以再次的被获取到,那么这个锁就是可重入锁。否则这个,锁就是不可重入锁。
public class ReentrantLock implements Lock, java.io.Serializable {
......
......
}
在 idea 打开这个类的时候,在 ReentrantLock 中存在三个内部类以及自己的一系列方法。一个公平锁的内部类,一个非公平锁的内部类,一个 Sync 类继承了抽象队列同步器,继承了相关的方法,可以使用多个等待条件实现同步
在类的顶部可以看到实现了 Lock 接口,也就是有了基本的显式声明锁,获取锁的能力。同时实现了序列化接。Serialization(序列化)是一种将对象以一连串的字节描述的过程;反序列化deserialization是一种将这些字节重建成一个对象的过程。 对象数据需要在网络中传输的时候,或者将 Java 独享保存早磁盘的时候,需要使用序列化以及反序列化。
// 创造出来一个不公平的锁
/**
* 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 引用调用的方法。所以说 ReentrantLock 就是一个基于 AQS 创建出来的可重入锁。一方面,ReentrantLock 具有自己特定的加锁,解锁的方法,另外一方便,由于这个类继承了 AQS ,所以具有 AQS 的特性。
/**
* 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.
*/
/**
尝试获取到锁,拿到锁的话返回 true, 否则返回 false;
如果是当前线程已经获取到了锁,是可以重入的,这个是重入的核心
*/
final boolean nonfairTryAcquire(int acquires) {
// 获取当前的线程,就是什么线程调用了这个方法
final Thread current = Thread.currentThread();
// state 是 AQS 提供的变量,通过这个变量可以控制锁被线程获取的次数
int c = getState();
if (c == 0) {
// 以为 c== 0 ,这个时候锁还是没有被线程获取到的
if (compareAndSetState(0, acquires)) {
// 由于锁还没有被使用,这个直接把锁给当前的线程
setExclusiveOwnerThread(current);
// 当前的线程获取到了锁,那么返回 true 即可
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
// current == getExclusiveOwnerThread()
// 当前线程和前面已经获取到锁的线程是一个线程,那么下面实现锁的重入
// 当前线程持有锁的时候, state + 1
int nextc = c + acquires;
// 记录所重入的次数
// 拥有锁的线程数量大于 MAX_INTEGER 会变为负数,所以是 overflow
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
// AQS 的 state 随着重入次数的增加而增加
setState(nextc);
return true;
}
// 如果一个线程既不是第一次获取到锁,也不能实现重入,那么就返回 false
return false;
}
protected final boolean tryRelease(int releases) {
// 计算一个线程释放了锁之后的 state 的值
int c = getState() - releases;
// 持有锁的线程不是当前的线程,那么无法释放资源的,谁拿了谁才能释放锁
if (Thread.currentThread() != getExclusiveOwnerThread())
// 抛出来异常,没有拿锁,竟然想要释放锁,不被允许
throw new IllegalMonitorStateException();
boolean free = false;
// state == 0 的时候,需要将 free 改为 true 表示已经释放了
// 同时把持有者的信息抹掉,其他的线程才能继续的获取到锁
if (c == 0) {
free = true; // 标志位修改
setExclusiveOwnerThread(null); // 持有锁的信息抹掉
}
// 因为持有锁的线程把锁放了,这里的 state 也就是变为了 0
setState(c);
// 释放成功,没有线程拿着这个锁了,free 就是 true, 其他的线程可以使用这个锁了
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
}
}
/**
* Sync object for non-fair locks
*/
/**
这个是 ReentrantLock 中的非公平锁的实现源码,默认使用的是非公平锁
*/
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() {
// 做一个 CAS 操作, CAS 成功,说明以前没有线程获取到锁
// 将当前线程独占锁,圈地
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
// 无法获取到锁,说明锁已经被占用了
// 调用下面的 acquare() 方法
// 注意:在 acquare() 中后面还有一系列的方法,这里没有展示出来
// 执行的逻辑就是:
// 1.持有锁的线程是自己,那么重入即可
// 2.持有锁的线程不是自己,那么去 AQS 中排队
// 3.在 AQS 中排队使用的是双向链表。addWaiter() 方法中创造结点,把需要排队的线程信息放进去
// 按照尾插法将需要排队的线程放进去 Node 结点中保存
acquire(1);
}
/**
在非公平锁中获取锁还有下面的一种方式,使用 tryAcquire()
走的是 nonfairTryAcquire() 这个方法
*/
protected final boolean tryAcquire(int acquires) {
// 在 nonfairTryAcquire(1) 方法中传递 1 进去
// 进去到上面解析的代码中,存在两种情况:
// 1.持有锁的线程是自己,那么重入即可
// 2.持有锁的线程不是自己,那么去 AQS 中排队
return nonfairTryAcquire(acquires);
}
}
按照排队的方式获取锁,FIFO 的原则,十分的公平
/**
* 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();
if (c == 0) {
/**
* 公平锁与非公平锁很大的一个区别是:
* 在尝试获取锁的时候,如果AQS的同步队列中有其他线程在等待获取锁
* 则尝试获取锁失败,需要进入AQS的同步队列排队
* hasQueuedPredecessors方法判断AQS的同步队列是否有线程在等待
*/
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 类型的对象,调用相关的 lock() 的等方法。
Sync 对象是基于公平锁实现还是基于非公平锁实现取决于构造方法。
这样通过构造方法实现了对于公平锁以及非公平锁的锁对象的控制。
/**
* 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();
}
/**
* Acquires the lock.
*
* Acquires the lock if it is not held by another thread and returns
* immediately, setting the lock hold count to one.
*
*
If the current thread already holds the lock then the hold
* count is incremented by one and the method returns immediately.
*
*
If the lock is held by another thread then the
* current thread becomes disabled for thread scheduling
* purposes and lies dormant until the lock has been acquired,
* at which time the lock hold count is set to one.
*/
public void lock() {
sync.lock();
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
/**
* Attempts to release this lock.
*
* If the current thread is the holder of this lock then the hold
* count is decremented. If the hold count is now zero then the lock
* is released. If the current thread is not the holder of this
* lock then {@link IllegalMonitorStateException} is thrown.
*
* @throws IllegalMonitorStateException if the current thread does not
* hold this lock
*/
public void unlock() {
sync.release(1);
}
public Condition newCondition() {
return sync.newCondition();
}
public int getHoldCount() {
return sync.getHoldCount();
}
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
/**
* Queries if this lock is held by any thread. This method is
* designed for use in monitoring of the system state,
* not for synchronization control.
*
* @return {@code true} if any thread holds this lock and
* {@code false} otherwise
*/
public boolean isLocked() {
return sync.isLocked();
}
/**
* Returns {@code true} if this lock has fairness set true.
*
* @return {@code true} if this lock has fairness set true
*/
public final boolean isFair() {
return sync instanceof FairSync;
}
protected Thread getOwner() {
return sync.getOwner();
}
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}
public final int getQueueLength() {
return sync.getQueueLength();
}
......
......
protected Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();
}
本文详细的介绍了 ReentrantLock 的源代码,本文从四个方面介绍:三个 ReentrantLock 的内部类以及 ReentrantLock 类本身的方法。ReentrantLock 的实现原理其实是基于 AQS 的,同时 ReentrantLock 实例化构造对象的时候,可以选择是公平锁还是不公平锁。