抽象队列同步器AQS

    AQS全名为AbstractQueuedSynchronizer,为java并发包中提供的类。提供了对资源占用,释放,线程的等待、唤醒等接口和具体实现,

可以用在各种需要控制资源争用的场景中。(ReentrantLock/CountDownLatch/Semphore)

   

    AQS中定义了八个比较重要的方法:

      acquire、acruireShared:定义了资源争用的逻辑,如果没拿到,则等待

      tryAcquire、tryAcquireShared:实际执行占用资源的逻辑,如何判定由使用者具体去实现

      release、releaseShared:定义资源释放的逻辑,释放之后,通知后续节点进行争抢

      tryRelease、tryReleaseShared:定义执行资源释放的操作,具体的AQS使用者去实现

    资源占用流程

   

     以ReentrantLock为例,分析AQS的使用。由于ReentrantLock是独占锁,所以会涉及到 acquire、tryAcquire、release、tryRelease四个方法。

 ReentrantLock中Sync类继承了AQS,其中关键代码如下:

abstract static class Sync extends AbstractQueuedSynchronizer {
       

        /**
         * Performs {@link Lock#lock}. The main reason for subclassing
         * is to allow fast path for nonfair version.
         */
        abstract void lock();

        ....
        /**
         *非公平获取锁,每次获取时都尝试获取一次,不管前面是否有其他
         *线程也在尝试获取,获取失败则加入等待队列
         * 获取成功则将锁持有者设为当前线程
         */
        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;
        }

 
        /**
         *尝试释放锁
         *即将state变量减一,当state为0时返回释放成功
         */
        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

       ...
    }

     ReentrantLock中有公平锁和非公平锁两种实现。在ReentrantLock中对应了两个类,NonfairSync和FairSync,它们都继承了Sync。

     FairSync关键代码如下:

static final class FairSync extends Sync {
       ···

        /**
         *加锁方法,首先调用tryAcquire方法,成功则获取锁
         *否则通过aqs提供的方法将当前线程加入等待队列
        */
        final void lock() {
            acquire(1);
        }

        /**
         *如果state为0则尝试获取锁,如果前面有线程也尝试获取锁则把当前线程加入等待队列
         *state不为0则则判断持有锁的线程是否时当前线程,是则state加一(锁的可重入机制)
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                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;
        }
    }

      NonfairSync关键代码如下:

static final class NonfairSync extends Sync {
        ···

        /**
         *非公平锁加锁时总是先尝试获取锁
         *即尝试通过CAS将state由0设为1
         * 设置失败则调用acquire方法
         */
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        /**
        * tryAcquire方法调用父类Sync的nonfairTryAcquire方法
        */
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

  接下来再查看ReentrantLock的加锁与解锁方法,即在调用Sync的acruire和release方法:

...
public void lock() {
        sync.lock();
}

...

public void unlock() {
        sync.release(1);
}
...
原文地址:https://www.cnblogs.com/wkzhao/p/10259752.html