AbstractQueuedSynchronizer的学习

不问归期 提交于 2020-02-28 22:32:02

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;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!