一.简单概括
1.1Java.util.concurrent juc包里面的类实现的核心是AQS(AbstractQueueSynchronizer)抽象队列同步器,要分析ReentrantLock的实现的原理,离不开分析AQS和AQS与ReentrantLock之间的关系
二.分析AQS(AbstractQueueSynchronizer)
2.1:AQS(AbstractQueueSynchronizer)抽象队列同步器的组成:
2.1.1:成员变量包括:
(1)exclusiveOwnerThread:互斥模式下,表示持有锁的当前线程
(2)tail:指向末尾节点
(3)head:指向头结点,当head节点为空的时候,表示没有任何的线程在等待
(4)stat-aqs:同步器的状态
2.1.2:AQS的原理:AQS可以看做一个同步监视器的实现,并且具有排队功能,当一个线程去获取AQS锁资源的时候,如果所资源已经被其他的线程占有,则会新建一个节点,进入到排队队列,这个排队队列也是由AQS自己来维护的,当锁资源被释放的时候,会唤醒下一个节点,尝试去获取锁资源
stat表示AQS的同步状态,他在juc里面有不同的实现:
(1)ReetrantLock:stat为0的时候,表示没有线程占有这个锁,可以获取,>=1的时候,表示有线程咱占有这个锁资源,不可以获取,>1的时候表示有锁的重入
(2)CountDownLatch:(等待其他线程结束,再继续执行线程),stat表示等于等待数量,当stat为0 的时候,执行线程。
(3)Semaphore:(可以设置同时持有这个对象线程数),stat表示还可以获取这个对象的线程数量,当stat为0 的时候,线程尝试获取的时候,会进入排队状态。
2.1.3:AQS有等待队列,等待队列的数据结构如下:
Node节点:AQS的Node节点除了head节点以外,其他的一个节点代表一个等待的线程,每个Node节点的结构如下:
(1)prev:前置节点
(2)next:后置节点
(3)thread:等待的线程
(4)waitstat:等待的状态:
.1:表示中断
.-1:表示阻塞挂起
.-2:表示等待condition

三.ReentrantLock的具体实现原理
3.1:ReentrantLock有公平锁和非公平锁的两种的实现的方式,FairSyn和NonFairSyn的两种的实现方式,他们都是作为ReentrantLock 的内部类,继承和实现了AQS(AbstractQueueSynchronizer)的Syn
3.2 :
1.首先来介绍一下 ReentrantLock的NonFairSyn(非公平实现),具体的使用:
//默认没有参数是创建非公平锁
ReentrantLock reentrantLock = new ReentrantLock();
//尝试获取锁
reentrantLock.lock();
//释放锁资源
reentrantLock.unlock();
2.分析reentrantLock.lock()方法:点击方法跳转,找到非公平的实现,
/**
* 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);
}
}
分析:
(1)第一步:compareAndSetState(0, 1),实际上利用CAS(原子操作)将stat设置成1,如果成功设置成1,则线程获取当前的锁资源,如果设置失败,则说明stat>=1,有其他的线程持有资源
CAS是一个比较并交换的操作,如果比较内存值与期望值0相等,这将内存值stat设置为1,线程获取到锁资源
(2)第二步:setExclusiveOwnerThread(Thread.currentThread()),成功设置为stat为1,获取到锁资源,这需要将ExclusiveOwnerThread设置为获取到锁资源的线程
(3)第三步:acquire(1),如果是设置stat失败,则需要重新尝试获取,或者进入排队
3.分析acquire方法:
第三步调用acquire方法,将会尝试再次回去锁资源,或者会进入排队等候队列,acquire方法是在AbstractQueuedSynchronizer里面实现的
public final void acquire(int arg) {
if (!tryAcquire(arg) &&//尝试再次的去获取锁资源
acquireQueued(addWaiter(AbstractQueuedSynchronizer.Node.EXCLUSIVE), arg))//如果获取不到就会进入排队等候队列
selfInterrupt();
}
4.分析tryAcquire方法
tryAcquire是在具体的子类里面实现的,他会尝试的再次去获取锁资源,如果是可重入获取锁资源,stat则会进行+1操作,而每次unlock都会将stat进行-1操作,直到stat为0,唤醒等待队列里面的下一个线程
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;
}
5.分析acquireQueued(addWaiter(Node.EXCLUSIVE), arg)方法
首先是addWaiter(Node.EXCLUSIVE)方法,他是由AQS实现的,他会将获取不到的锁资源的线程,组装成一个node节点,然后添加到等待队列里面,这里线程并没有被挂起
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);//创建一个新的node节点,传入当前的线程,mode则表示为互斥模式
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;//前一个为之前的最后一个
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {//比较并设置为末尾
pred.next = node;
return node;
}
}
enq(node);
return node;
}
然后分析acquireQueued方法:
acquireQueued方法其实就是为了减少线程挂起、唤醒次数而作的优化操作。
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();//获取当前节点的前置节点
if (p == head && tryAcquire(arg)) {//第一步,如果前置节点是head,该节点的线程则不会挂起,会继续尝试获取锁资源,这样就避免了线程切换的成本
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&//第二部,我们首先会检查这个线程是否需要被挂起,当节点waitstat为-1的才挂起,parkAndCheckInterrupt,挂起
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
本文详细解析了Java中ReentrantLock的实现原理,重点介绍了AQS(AbstractQueueSynchronizer)的作用与机制,包括其核心组件如exclusiveOwnerThread、tail、head、state以及Node节点的结构和功能。同时,探讨了ReentrantLock的公平锁和非公平锁的实现差异。
1453

被折叠的 条评论
为什么被折叠?



