什么是AQS及其原理

GitHub:https://github.com/JDawnF

1、AQS简介

AQS全名:AbstractQueuedSynchronizer,是并发容器J.U.C(java.util.concurrent)下locks包内的一个类。它实现了一个FIFO(FirstIn、FisrtOut先进先出)的队列。底层实现的数据结构是一个双向链表

Sync queue:同步队列,是一个双向链表。包括head节点和tail节点。head节点主要用作后续的调度。 Condition queue:非必须,单向链表。当程序中存在cindition的时候才会存在此列表。

AQS核心思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制AQS是用CLH队列锁实现的,即将暂时获取不到锁的线程加入到队列中。

AQS使用一个int成员变量来表示同步状态,通过内置的FIFO队列来完成获取资源线程的排队工作。AQS使用CAS对该同步状态进行原子操作实现对其值的修改。

状态信息通过protected类型的getState,setState,compareAndSetState进行操作

//返回同步状态的当前值
protected final int getState() {  
        return state;
}
 // 设置同步状态的值
protected final void setState(int newState) { 
        state = newState;
}
//原子地(CAS操作)将同步状态值设置为给定值update如果当前同步状态的值等于expect(期望值)
protected final boolean compareAndSetState(int expect, int update) {
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

2、AQS设计思想

  • 使用Node实现FIFO队列,可以用于构建锁或者其他同步装置的基础框架。

  • 利用int类型标识状态。在AQS类中有一个叫做state的成员变量

      /**
       * The synchronization state.
       */
      private volatile int state;
  • 基于AQS有一个同步组件,叫做ReentrantLock。在这个组件里,stste表示获取锁的线程数,假如state=0,表示还没有线程获取锁,1表示有线程获取了锁。大于1表示重入锁的数量。

  • 继承:子类通过继承并通过实现它的方法管理其状态(acquire和release方法操纵状态)。

  • 可以同时实现排它锁和共享锁模式(独占、共享),站在一个使用者的角度,AQS的功能主要分为两类:独占和共享。它的所有子类中,要么实现并使用了它的独占功能的api,要么使用了共享锁的功能,而不会同时使用两套api,即便是最有名的子类ReentrantReadWriteLock也是通过两个内部类读锁和写锁分别实现了两套api来实现的。

3、AQS的大致实现思路

AQS内部维护了一个CLH队列来管理锁。线程会首先尝试获取锁,如果失败就将当前线程及等待状态等信息包装成一个node节点加入到同步队列sync queue里。 接着会不断的循环尝试获取锁,条件是当前节点为head的直接后继才会尝试。如果失败就会阻塞自己直到自己被唤醒。而当持有锁的线程释放锁的时候,会唤醒队列中的后继线程。

CLH(Craig,Landin,and Hagersten)队列是一个虚拟的双向队列(虚拟的双向队列即不存在队列实例,仅存在结点之间的关联关系)。AQS是将每条请求共享资源的线程封装成一个CLH锁队列的一个结点(Node)来实现锁的分配。

 

 

推荐两篇文章:

参照:https://blog.csdn.net/jesonjoke/article/details/80054133

https://github.com/JDawnF/JavaGuide/blob/master/Java%E7%9B%B8%E5%85%B3/Multithread/AQS.md

觉得有收获的,可以来一波赞赏!

### AQS在Java锁实现中的原理与应用 #### 1. 基本概念 AQS(AbstractQueuedSynchronizer)是一个用于构建锁和其他同步组件的基础框架。它通过内部维护的一个状态变量 `state` 来表示资源的状态,并利用 FIFO 队列管理线程的排队行为[^1]。 #### 2. 核心功能 AQS 提供的核心功能包括但不限于以下几个方面: - **阻塞式获取锁 (`acquire()`)**:当线程试图获取锁时,如果当前状态不允许,则该线程会被加入到等待队列中并被挂起。 - **非阻塞式尝试获取锁 (`tryAcquire()`)**:允许线程快速判断是否可以成功获取锁而不进入阻塞状态。 - **超时机制**:支持带有时间限制的锁获取操作,防止死锁或长时间占用资源。 - **中断处理**:提供对线程中断的支持,使得线程可以在等待过程中响应外部信号。 - **独占模式 vs 共享模式**:AQS 支持两种主要的操作模式——独占模式(适用于单一线程访问场景)和共享模式(允许多个线程同时访问)。这两种模式分别对应于不同的锁类型,例如 ReentrantLock 使用的是独占模式,而 Semaphore 则使用共享模式[^2]。 #### 3. 实现细节 ##### (1)状态管理 AQS 中的关键字段是 `volatile int state`,这是一个原子整数,用来记录同步状态的变化情况。子类可以通过继承 AQS 并重写其方法来自定义具体的逻辑。以下是几个重要的抽象方法及其默认实现方式: - `protected boolean tryAcquire(int arg)`:尝试以独占的方式获取指定数量的许可,默认抛出异常。 - `protected boolean tryRelease(int arg)`:释放指定数量的许可,默认返回 false 表示未完全释放。 - `protected int tryAcquireShared(int arg)`:尝试以共享的方式获取指定数量的许可,默认返回负值表示失败。 - `protected boolean tryReleaseShared(int arg)`:释放共享式的许可,默认返回 false 表示未能完成释放。 ##### (2)FIFO 队列结构 为了协调多个竞争线程之间的关系,AQS 维护了一条双向链表形式的等待队列。每当有新的请求到来却无法立即得到满足时,就会创建一个新的节点并将之插入到队尾位置上形成有序排列[^4]。 ##### (3)CAS 操作 在修改同步状态的过程中广泛采用了无锁算法技术—Compare And Swap(CAS),从而保证了高并发环境下的安全性以及效率最大化。例如,在 FairSync 类型下实现了公平策略的具体做法就是调用了父类的方法 `acquire(arg)` 进一步触发底层 CAS 调用: ```java final void lock() { acquire(1); } ``` #### 4. 应用案例分析 下面给出一段简单的代码片段展示如何基于 AQS 构建一个自定义不可重入互斥锁实例: ```java class MyMutex extends AbstractQueuedSynchronizer { @Override protected boolean isHeldExclusively() { return getState() == 1; } public void lock() { acquire(1); } public void unlock() { release(1); } @Override protected boolean tryAcquire(int acquires) { if (compareAndSetState(0, 1)) { setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } @Override protected boolean tryRelease(int releases) { if (getState() == 0) throw new IllegalMonitorStateException(); setExclusiveOwnerThread(null); setState(0); return true; } } MyMutex mutex = new MyMutex(); mutex.lock(); // 获取锁 // 执行临界区代码... mutex.unlock(); // 释放锁 ``` 上述例子展示了最基础的功能封装过程,实际项目开发当中还可以进一步扩展更多特性比如设置超时参数等功能。 ---
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值