【AQS我可以讲十分钟】

AQS详解:Java并发工具AbstractQueuedSynchronizer核心原理与应用

在这里插入图片描述

AQS的全称是AbstractQueuedSynchronizer,也就是抽象队列同步器,它是在java.util.concurrent.locks包下的,也就是JUC并发包。java提供了synchronized关键字内置锁,还提供了显示锁,而大部分的显示锁的底层都用到了AQS,比如只有一个线程能执行ReentrantLock独占锁,又比如多个线程可以同时执行共享锁Semaphore、CountDownLatch、ReadWriteLock,CyclicBarrier。AQS使用模板方法模式,使用者继承AbstractQueuedSynchronizer并重写指定的方法,重写的方法就是对于共享资源state的获取和释放,将AQS在自定义同步组件的实现中,调用它的模板方法,这些模板方法会调用使用者重写的方法,这是模板方法模式很经典的一个运用。另外AQS还维护了一个变量volatile int state,代表了加锁的状态,初始状态下,state的值是0。另外还有一个虚拟的双向队列,这个队列是不存在的,它是抽象的概念,存在结点之间的关联关系,它会将请求共享资源的线程,封装成一个Node结点来实现锁的分配。除此之外AQS内部还有一个线程变量,用来记录当前加锁的是哪个线程,初始化状态下,这个变量是null。拿ReentrantLock加锁举例,线程调用ReentrantLock的lock()方法进行加锁,这个加锁的过程,用CAS将state值从0变为1。一旦线程加锁成功了之后,就可以设置当前加锁线程是自己。ReentrantLock通过多次执行lock()加锁和unlock()释放锁,对一个锁加多次,从而实现可重入锁,每次线程可重入加锁一次,判断一下当前加锁线程是不是自己,如果是他自己就可以可重入多次加锁,每次加锁,就是把state的值给累加1。当state=1时代表当前对象锁已经被占用,其他线程来加锁时则会失败,然后再去看加锁线程的变量里面是不是自己之前占用过这把锁,如果不是就说明有其他线程占用了这个锁,失败的线程被放入一个等待队列中,在等待唤醒的时候,经常会使用自旋(while(!cas()))的方式,不停地尝试获取锁,等待已经获得锁的线程,释放锁才能被唤醒。当它释放锁的时候,将AQS内的state变量的值减1,如果state值为0,就彻底释放锁,会将“加锁线程”变量设置为null。这个时候,会从等待队列的队头唤醒其他线程重新尝试加锁,获得锁成功之后,会把“加锁线程”设置为线程自己,同时线程自己就从等待队列中出队。这个就是aqs实现自旋锁,可重入锁,独占锁的底层实现。接着拿CountDownLatch举例,任务分为5个子线程去执行,state也初始化为5。这5个子线程是并行执行的,每个子线程执行完后countDown()一次,state会CAS减1,等到所有子线程都执行完后,state=0,会unpark()主调用线程,然后主调用线程就会从await()函数返回,继续后余动作。

在这里插入图片描述

整个图片,歇歇眼,文章大多不换行,排版基本都是一块的,一千三百字,口速快的话,十分钟差不多可以讲完,这篇博文主要是针对面试口述的,备战面试。

08-20
AQS,全称为 AbstractQueuedSynchronizer,是 Java 中 `java.util.concurrent.locks` 包内的一个抽象类,它作为构建锁和其他同步组件的基础框架[^2]。AQS 的核心设计目标是为实现同步机制提供一种通用的、可扩展的结构,支持独占模式(如 ReentrantLock)和共享模式(如 CountDownLatch)两种同步状态的获取方式[^1]。 AQS 通过一个 `int` 类型的成员变量来表示同步状态,用于追踪共享资源的状态(例如锁是否被占用)[^3]。其内部实现依赖于一个 FIFO 的双向队列,也被称为同步队列。该队列是一个双向链表结构,用于管理那些未能成功获取同步状态的线程。当线程尝试获取锁失败时,会被封装成一个节点(Node),并被加入到队列中进行阻塞等待;当资源释放时,会从队列头部开始唤醒等待的线程,使其再次尝试获取同步状态[^4]。 AQS 提供了对同步状态的原子操作方法,包括 `getState()`、`setState(int newState)` 和 `compareAndSetState(int expect, int update)`,这些方法确保了在多线程环境下对同步状态的修改是线程安全的[^3]。此外,AQS 的设计鼓励子类通过继承并实现其抽象方法来定义特定的同步逻辑,从而支持了灵活的同步组件开发。 常见的基于 AQS 构建的同步组件包括 `ReentrantLock`(可重入锁)、`CountDownLatch`(倒计时门闩)、`CyclicBarrier`(循环屏障)和 `Semaphore`(信号量)等。 ```java // 示例:基于 AQS 实现的简单锁 public class SimpleLock extends AbstractQueuedSynchronizer { // 尝试获取锁 protected boolean tryAcquire(int acquires) { if (compareAndSetState(0, 1)) { setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } // 尝试释放锁 protected boolean tryRelease(int releases) { setState(0); setExclusiveOwnerThread(null); return true; } // 获取锁的方法 public void lock() { acquire(1); } // 释放锁的方法 public void unlock() { release(1); } } ``` 上述代码展示了一个基于 AQS 的简单锁实现,通过重写 `tryAcquire` 和 `tryRelease` 方法来控制同步状态的获取与释放。
评论 26
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java程序员廖志伟

赏我包辣条呗

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值