JUC之AQS框架

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zteny/article/details/54919765

一、简介

1. AQS

AQS是AbstractQueuedSynchronizer的简写,中文名应该叫抽象队列同步器(我给的名字,哈哈),出生于Java 1.5

Provides a framework for implementing blocking locks and related synchronizers (semaphores, events, etc) that rely on first-in-first-out (FIFO) wait queues. This class is designed to be a useful basis for most kinds of synchronizers that rely on a single atomic int value to represent state. Subclasses must define the protected methods that change this state, and which define what that state means in terms of this object being acquired or released. Given these, the other methods in this class carry out all queuing and blocking mechanics. Subclasses can maintain other state fields, but only the atomically updated int value manipulated using methods getState, setState and compareAndSetState is tracked with respect to synchronization. ——Java docs

翻开源码,首先是一大段的注释,然后可以看开AQS继承自AbstractOwnableSynchronizer。当你翻开AbstractOwnableSynchronizer时,还是先看到小段的说注释。

A synchronizer that may be exclusively owned by a thread. This class provides a basis for creating locks and related synchronizers that may entail a notion of ownership. The AbstractOwnableSynchronizer class itself does not manage or use this information. However, subclasses and tools may use appropriately maintained values to help control and monitor access and provide diagnostics. ——Java docs

2. AOS

她生自Java 1.6

可以由线程以独占方式拥有的同步器。此类为创建锁和相关同步器(伴随着所有权的概念)提供了基础。AbstractOwnableSynchronizer 类本身不管理或使用此信息。但是,子类和工具可以使用适当维护的值帮助控制和监视访问以及提供诊断。

简言之,AOS(容我先如此缩写吧)输出的是一种概念,是一种创建独占式同步器所有权的概念。她自身并没有规范所有权的管理方式,更没有用到这些信息(所有权的信息)。不过呢,可以帮其子类维护所有者信息。
可以你并不能理解上面这一小段话,不过没关系接着看源码就是了。
AOS提供两个方法一个字段,外带一个空构造方法(可无视之)。

/**
 * The current owner of exclusive mode synchronization.
 */
private transient Thread exclusiveOwnerThread; // transient表示该字段不需要序列化,因为AOS实现了Serializable

protected final void setExclusiveOwnerThread(Thread thread) {
    exclusiveOwnerThread = thread;
}

protected final Thread getExclusiveOwnerThread() {
    return exclusiveOwnerThread;
}

这下明白了吧,就是AOS啥都没有就只维护一个东西——当前谁持有独占式同步器。因此咱们可以当它不存在吧,继续回到重点AQS。

You may also find the inherited methods from {@link AbstractOwnableSynchronizer} useful to keep track of the thread owning an exclusive synchronizer. You are encouraged to use them – this enables monitoring and diagnostic tools to assist users in determining which threads hold locks. – Java Docs

二、作用

Java Docs的注释可以知道,AQS是一个框架,一个提供锁或同步器依赖于FIFO等待队列所必要的“基础设施”的框架。Doug Lea之所以写个抽象类的目的是为了简化我们实现同步器的工作。

换句话说,

提供一个基于FIFO等待队列,可以用于构建锁或者其他同步装置的基础框架。意在能够成为实现大部分同步需求的基础

AQS默认提供了独占式共享式两种模式,JDK对应的实现有ReentrantLockReentrantReadWriteLock。即除了提供acquire方法之外,还提供了acquireShare。带shared都是共享模式相关操作,默认则是独占模式。

AQS到底提供了哪些便利呢:
1. 管理状态
2. 实现了线程安全的CLH队列
3. 实现了同步器公共方法
4. ConditionObject

三、原理

AQS自身就是一个Wait QueueCLH lock queue的变种,CLH队列通常用于自旋锁

The wait queue is a variant of a “CLH” (Craig, Landin, and Hagersten) lock queue. CLH locks are normally used for spinlocks. We instead use them for blocking synchronizers, but use the same basic tactic of holding some of the control information about a thread in the predecessor of its node.

我们知道Queue的底层实现是一个链表结构,我们也知道它可以是单链表,也可以是双链表。AQS实现的是一个双链表结构。即每个节点都存储了前驱和后继两个指针,而且Head节点是dummy节点。入队则tail前驱一个节点,再把新节点接入,然后接入tail节点。

AQS完全通过CAS解决多线程安全问题,即通过Unsafe完成的。具体可以自行阅读AQS源码,在最后几个方法,非常简单。

CAS : compareAndSet,Unsafe的CAS方法的语义是先与期望值进行比较,若不相等返回false;若相等的话,则会把原值修改新值,再返回true。这个跟java.util.concurrent.atomic的原子类的CAS方法是一样一样的。

AQS的实现依赖LockSupport完成阻塞和唤醒,也正是LockSupport的引入使得AQS源码阅读起来逻辑上有点跳跃。不过没关系,后面我们梳理Java Lock的时候,会把LockSupport重新拿出来看的。

什么是自旋锁,如下示例实现的即是自旋锁,即是循环等待信号量变成期望值后完成相关操作。

// 来自 AQS#doAcquireInterruptibly
private void doAcquireInterruptibly(int arg) throws InterruptedException {
    final Node node = addWaiter(Node.EXCLUSIVE);
    boolean failed = true;
    try {
        for (;;) { // 自旋锁
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) { // 相当于阻塞到信号量变成期望值
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return;
            }
            if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
                throw new InterruptedException();
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

除此之外,AQS提供一些与同步器业务相关的一些方法,如:acquire和release。另外还有一些与Queue监控相关的方法。

AQS提供的所有方法的分类列表:
1. Queuing utilities
2. Utilities for various versions of acquire
cancelAcquire
3. Main exported methods
tryAcquire
releaseShared
4. Queue inspection methods
hasQueuedThreads
5. Instrumentation and monitoring methods
getQueueLength
6. Interenal support methdos for Conditions
isOnSyncQueue
7. Instrumentation methods for conditions
owns
8. Internal methods
addConditionWaiter
9. public methods
10. for interruptible waits, we need to track whether to throw InterruptedException,….
11. Support for instrumentation
isOwnedBy
12. CAS : unsafe

四、用法

AQS的用法,可以直接参考AQS的注释,另外也可以参考ReentrantLock的写法。
通过比外提供两个方法acquirerelease的源码可知,它们是通过调用对应protected的try方法完成的。

public final void acquire(int arg) {
    if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

注释指出了,继承AQS需要实现下面五个方法,

tryAcquire(int arg)
tryRelease(int arg)
tryAcquireShared(int arg)
tryReleaseShared(int arg)
isHeldExclusively()

它们带的int参数,用来表示状态,如下面示例中,用了10表示锁和释放。
如你所知,前两个是独占式,中间两个是共享式。最后是测试当是同步器是否正被持有独占锁。即是已经有线程持有这个排他锁,且还未释放。

下面是AQS注释里提供的实现。

class Mutex implements Lock, java.io.Serializable {

    // Our internal helper class
    private static class Sync extends AbstractQueuedSynchronizer {
        // Report whether in locked state
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        // Acquire the lock if state is zero
        public boolean tryAcquire(int acquires) {
            assert acquires == 1; // Otherwise unused
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        // Release the lock by setting state to zero
        protected boolean tryRelease(int releases) {
            assert releases == 1; // Otherwise unused
            if (getState() == 0)
                throw new IllegalMonitorStateException();
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        // Provide a Condition
        Condition newCondition() {
            return new ConditionObject();
        }

        // Deserialize properly
        private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }

    // The sync object does all the hard work. We just forward to it.
    private final Sync sync = new Sync();

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

    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    public void unlock() {
        sync.release(1);
    }

    public Condition newCondition() {
        return sync.newCondition();
    }

    public boolean isLocked() {
        return sync.isHeldExclusively();
    }

    public boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }

    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }
}

猜你喜欢

转载自blog.csdn.net/zteny/article/details/54919765