AQS——同步器框架之源

1. AQS原理

AQSAbstractQueuedSynchronizer的简称。AQS提供了一种实现阻塞锁和一系列依赖FIFO等待队列的同步器的框架。

1.1 AQS的继承关系

ReentrantLockSemaphore之间的继承体系

1.2 AQS的实现原理

AQS中 维护了一个整型变量 state(代表共享资源)和一个FIFO线程等待队列(多线程争用资源被阻塞时会进入此队列)。

  • state 初始化 0,在多线程条件下,线程要执行临界区的代码,必须首先获取 state,某个线程获取成功之后, state 加 1,其他线程再获取的话由于共享资源已被占用,所以会到 FIFO 等待队列去等待,等占有 state 的线程执行完临界区的代码释放资源( state 减 1)后,会唤醒 FIFO 中的下一个等待线程(head 中的下一个结点)去获取 state。

  • state 由于是多线程共享变量,所以必须定义成 volatile,以保证 state 的可见性, 同时虽然 volatile 能保证可见性,但不能保证原子性,所以 AQS 提供了对 state 的原子操作方法,保证了线程安全。

  • 另外 AQS 中实现的 FIFO 队列(CLH 队列)其实是双向链表实现的,由 head, tail 节点表示,head 结点代表当前占用的线程,其他节点由于暂时获取不到锁所以依次排队等待锁释放。

java 复制代码
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizerimplements java.io.Serializable {
    // 以下为双向链表的首尾结点,代表入口等待队列
    private transient volatile Node head;
    private transient volatile Node tail;
    // 共享变量 state
    private volatile int state;
    // cas 获取 / 释放 state,保证线程安全地获取锁
    protected final boolean compareAndSetState(int expect, int update) {
        // See below for intrinsics setup to support this\
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }
 }

2. 源码解析

通过对ReentrantLock独占锁源码的分析,来理解AQS的底层原理,共享锁与 Condition 的实现与独占锁和非公平锁原理相似,在此不过多阐述。

java 复制代码
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);
    }
}
java 复制代码
static final class FairSync extends Sync {
    private static final long serialVersionUID = -3000897897090466540L;

    final void lock() {
        acquire(1);
    }

    /**
     * Fair version of tryAcquire.  Don't grant access unless
     * recursive call or no waiters or is first.
     */
    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;
    }
}
java 复制代码
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

相关链接

我画了35张图就是为了让你深入 AQS
1.5w字,30图带你彻底掌握 AQS!

相关推荐
小杨40412 分钟前
springboot框架项目实践应用三(监控运维组件admin)
spring boot·后端·监控
sevevty-seven2 小时前
Spring Boot 自动装配原理详解
java·spring boot·后端
lamdaxu2 小时前
分布式调用(02)
后端
daiyunchao2 小时前
让Pomelo支持HTTP协议
后端
SaebaRyo3 小时前
手把手教你在网站中启用https和http2
后端·nginx·https
A-Kamen3 小时前
Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现与实战指南
java·spring boot·后端
豆豆酱3 小时前
Transformer结构详解
后端
upsilon3 小时前
golang切片slice
后端·go
狂奔小菜鸡3 小时前
Java运行时数据区
java·jvm·后端