AbstractQueuedSynchronizer
public class AQSDemo implements Lock {
private Sycn sycn = new Sycn();
//实现同步器
private class Sycn extends AbstractQueuedSynchronizer{
@Override
protected boolean tryAcquire(int arg) { //尝试获取锁的方法
//如果第一个线程进来,可以拿到锁,因此我们可以返回true
//如果第二个线程进来,拿不到锁,返回false
//如何判断是第一个线程进来还是其他线程进来?
//getState()方法返回 1 表示 锁被线程持有 0表示锁没被线程持有
int state = getState();
if(state==0){
if(compareAndSetState(0, arg)){ //更新状态
setExclusiveOwnerThread(Thread.currentThread());//设置为当前线程
return true; //获取到锁
}
}
return false; //没有获取到锁
}
@Override
protected boolean tryRelease(int arg) { //释放锁的方法
//锁的获取和释放肯定是一一对应的,那么调用此方法的线程一定是当前线程
if(Thread.currentThread()!=getExclusiveOwnerThread()){
throw new RuntimeException();
}
int state = getState()-arg;//释放锁扣减1
boolean flag = false;
if(state==0){//判断是否把锁释放
setExclusiveOwnerThread(null);//设置空
flag = true; // 释放成功
}
setState(state); //设置状态
return flag; //释放失败
}
Condition newCondition(){ //用来线程通信
return new ConditionObject();
}
}
//下面是Lock接口的需要实现的方法
@Override
public void lock() {
sycn.acquire(1); //它的内部会调用重写的tryAcquire方法判断
}
@Override
public void lockInterruptibly() throws InterruptedException {
sycn.acquireInterruptibly(1);
}
@Override
public boolean tryLock() {
return sycn.tryAcquire(1);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return sycn.tryAcquireNanos(1,unit.toNanos(time));
}
@Override
public void unlock() {
sycn.release(1);
}
@Override
public Condition newCondition() {
return sycn.newCondition();
}
}
AQS的源码分析
AbstractQueuedSynchronizer提供获取锁的方法
public final void acquire(int arg) {
// tryAcquire先尝试获取"锁",获取了就不进入后续流程
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
//addWaiter是给当前线程创建一个节点,并将其加入等待队列
//acquireQueued是当线程已经加入等待队列之后继续尝试获取锁.
selfInterrupt();
}
ReentranLock的tryAcquire方法实现
//AbstractQueuedSynchronizer的tryAcquire方法重写用来判断尝试获取锁的方法
//AQS类中的变量.
private volatile int state;
//这是FairSync的实现,AQS中未实现,子类按照自己的需要实现该函数
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
//获取AQS中的state变量,代表抽象概念的锁.
int c = getState();
if (c == 0) { //值为0,那么当前独占性变量还未被线程占有
//如果当前阻塞队列上没有先来的线程在等待,UnfairSync这里的实现就不一致
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
//成功cas,那么代表当前线程获得该变量的所有权,也就是说成功获得锁
setExclusiveOwnerThread(current);
// setExclusiveOwnerThread将本线程设置为独占性变量所有者线程
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
//如果该线程已经获取了独占性变量的所有权,那么根据重入性
//原理,将state值进行加1,表示多次lock
//由于已经获得锁,该段代码只会被一个线程同时执行,所以不需要
//进行任何并行处理
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
//上述情况都不符合,说明获取锁失败
return false;
}
如果tryAcquire返回true,那么就是获取锁成功;如果返回false,那么就是未获得锁,需要加入阻塞等待队列。我们下面就来看一下addWaiter的相关操作。
等待锁的阻塞队列
//AbstractQueuedSynchronizer提供
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
//先使用快速入列法来尝试一下,如果失败,则进行更加完备的入列算法.
//只有在必要的情况下才会使用更加复杂耗时的算法,也就是乐观的态度
Node pred = tail; //列尾指针
if (pred != null) {
node.prev = pred; //步骤1:该节点的前趋指针指向tail
if (compareAndSetTail(pred, node)){ //步骤二:cas将尾指针指向该节点
pred.next = node;//步骤三:如果成果,让旧列尾节点的next指针指向该节点.
return node;
}
}
//cas失败,或在pred == null时调用enq
enq(node);
return node;
}
private Node enq(final Node node) {
for (;;) { //cas无锁算法的标准for循环,不停的尝试
Node t = tail;
if (t == null) { //初始化
if (compareAndSetHead(new Node()))
//需要注意的是head是一个哨兵的作用,并不代表某个要获取锁的线程节点
tail = head;
} else {
//和addWaiter中一致,不过有了外侧的无限循环,不停的尝试,自旋锁
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
等待队列节点的操作
//AbstractQueuedSynchronizer提供
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) { //一直执行,直到获取锁,返回.
final Node p = node.predecessor();
//node的前驱是head,就说明,node是将要获取锁的下一个节点.
if (p == head && tryAcquire(arg)) { //所以再次尝试获取独占性变量
setHead(node); //如果成果,那么就将自己设置为head
p.next = null; // help GC
failed = false;
return interrupted;
//此时,还没有进入阻塞状态,所以直接返回false,表示不需要中断调用selfInterrupt函数
}
//判断是否要进入阻塞状态.如果`shouldParkAfterFailedAcquire`
//返回true,表示需要进入阻塞
//调用parkAndCheckInterrupt;否则表示还可以再次尝试获取锁,继续进行for循环
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
//调用parkAndCheckInterrupt进行阻塞,然后返回是否为中断状态
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL) //前一个节点在等待独占性变量释放的通知,所以,当前节点可以阻塞
return true;
if (ws > 0) { //前一个节点处于取消获取独占性变量的状态,所以,可以跳过去
//返回false
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
//将上一个节点的状态设置为signal,返回false,
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this); //将AQS对象自己传入
return Thread.interrupted();
}
unlock操作
//AbstractQueuedSynchronizer实现的提供的获取锁的方法
public final boolean release(int arg) {
if (tryRelease(arg)) {
//释放独占性变量,起始就是将status的值减1,因为acquire时是加1
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);//唤醒head的后继节点
return true;
}
return false;
}
需要重写方法tryRelease(int releases)
//AbstractQueuedSynchronizer的tryRelease(int releases)需要重写的方法尝试释放锁的
protected final boolean tryRelease(int releases) {
//由于只有一个线程可以获得独占先变量,所以,所有操作不需要考虑多线程
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) { //如果等于0,那么说明锁应该被释放了,否则表示当前线程有多次lock操作.
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
来源:CSDN
作者:qq_43382364
链接:https://blog.csdn.net/qq_43382364/article/details/104562478