【JUC 并发编程】— AQS 概述与实例
2022/6/9 1:21:34
本文主要是介绍【JUC 并发编程】— AQS 概述与实例,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
介绍
队列同步器 AbstractQueuedSynchronizer,简称为 AQS,是用来构建锁及其他同步组件(比如 ReentrantLock、CountDownLatch)的基础框架。它使用了一个 int 成员变量表示同步状态,通过内置的 FIFO 队列来完成获取资源线程的排队工作。AQS 的主要使用方式是继承,子类被推荐被定义为自定义同步组件的静态内部类,通过实现同步器的一些protected方法。 如果一个类想成为状态依赖的类,那么它必须拥有一些状态。AQS 负责管理同步器类的状态,可以通过 getState、setState 以及 compareAndSetState 等 protected 类型方法来进行操作。
如果某个同步器支持独占式操作,那么需要实现一些 protected 方法,包括 tryAcquire、tryRelease 和 isHeldExclusively 等;而对于支持共享获取的同步器,则应该实现 tryAcquireShared 和 tryReleaseShared 等方法。
AQS 是实现锁(也可以是任意同步组件)的关键,在锁的实现中聚合同步器,利用同步器实现锁的语义。可以这样理解二者之间的关系:
琐是面向使用者的,它定义了使用者与锁交互的接口,隐藏了实现细节;同步器面向锁的,它简化了锁的实现方式,屏蔽了同步状态的管理、线程的排队、等待与唤醒等底层操作。锁和同步器很好的隔离了使用者和实现者所需关注的领域。
接口
同步器的设计设计是基于模板方式模式的,也就是说,使用者需要继承同步器并重写指定的方法。
同步状态相关方法
重写同步器指定的方法时,需要使用到同步器提供的一下三个方法来访问或修改同步状态:
/** * 获取同步状态 * Returns the current value of synchronization state. * * 这个操作有 volatile 读的内存语义,也就是说总是从主内存获取,保证同步状态是最新的 * This operation has memory semantics of a <tt>volatile</tt> read. * @return current state value */ protected final int getState() { return state; } /** * 设置同步状态 * Sets the value of synchronization state. * * 这个操作有 volatile 写的内存语义,也就是写完就同步到主内存 * This operation has memory semantics of a <tt>volatile</tt> write. * @param newState the new state value */ protected final void setState(int newState) { state = newState; } /** * CAS 方式设置状态,有 volatile 的读写内存语义 * Atomically sets synchronization state to the given updated * value if the current state value equals the expected value. * This operation has memory semantics of a <tt>volatile</tt> read * and write. */ protected final boolean compareAndSetState(int expect, int update) { // See below for intrinsics setup to support this return unsafe.compareAndSwapInt(this, stateOffset, expect, update); }
可重写方法
自定义同步组件内部静态类(推荐使用)需重写同步器 protected 方法如下:
方法名称 | 描述 |
---|---|
protected boolean tryAcquire(int arg) | 独占式获取同步状态,实现该方法需要判断当前的同步状态是否符合预期,然后再 CAS 设置同步状态 |
protected boolean tryRelease(int arg) | 独占式释放同步状态 |
protected int tryAcquireShared(int arg) | 共享式获取同步状态,返回 >=0 的值,表去获取成功,反之失败 |
protected int tryReleaseShared(int arg) | 共享式释放不同状态 |
protected boolean isHeldExclusively() | 当前同步器在独占式模式下是否被占用 |
模板方法
自定义同步组件时,将会调用同步器的模板方法,如下:
独占式
方法名称 | 描述 |
---|---|
void acquire(int arg) | 独占式获取同步状态,不响应中断 |
void acquireInterruptibly(int arg) | 与 acquire(int arg) 相同,但响应中断 |
boolean tryAcquireNanos(int arg, long nanosTimeout) | 在 acquireInterruptibly(int arg) 基础上增加超时限制 |
boolean release(int arg) | 独占式释放同步状态 |
共享式
方法名称 | 描述 |
---|---|
void acquireShared(int arg) | 共享式获取 |
void acquireSharedInterruptibly(int arg) | 与 acquireShared(int arg) 相同,响应中断 |
boolean tryAcquireSharedNanos(int arg, long nanosTimeout) | 在 acquireSharedInterruptibly(int arg) 基础上增加超时限制 |
boolean releaseShared(int arg) | 共享式释放 |
等待队列信息
方法名称 | 描述 |
---|---|
Collection |
获取等待在同步队列上的线程集合 |
实例
下面代码是独占锁的简单实现
/** * 通过 AQS 自定义同步组件 * * @author LBG - 2017/11/8 0008 */ public class Mutex { private final Sync sync = new Sync(); public void lock() { sync.acquire(1); } public boolean tryLock() { return sync.tryAcquire(1); } /** * 限时获取,可中断 */ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } public boolean unlock() { return sync.release(1); } public boolean isLocked() { return sync.isHeldExclusively(); } public void lockInterruptible() throws InterruptedException { sync.acquireInterruptibly(1); } /** * 静态内部类,继承同步器 */ private class Sync extends AbstractQueuedSynchronizer { /** * 当状态为0 时获取锁,并把状态改为1 */ @Override protected boolean tryAcquire(int arg) { if (compareAndSetState(0, 1)) { setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } /** * 释放锁,将状态设为0 */ @Override protected boolean tryRelease(int arg) { if (getState() == 0) { throw new IllegalMonitorStateException(); } setExclusiveOwnerThread(null); setState(0); return true; } /** * 是否处于独占状态,1 表示独占 */ @Override protected boolean isHeldExclusively() { return getState() ==1; } } }
本篇主要是对 AQS 有个基本的了解,以及主要方法的作用和使用,接下来则按独占式和共享式分别对其源码进行分析。
参考资料:
- Java并发编程实战
- Java并发编程的艺术
- 深入理解Java虚拟机(第2版)
这篇关于【JUC 并发编程】— AQS 概述与实例的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23增量更新怎么做?-icode9专业技术文章分享
- 2024-11-23压缩包加密方案有哪些?-icode9专业技术文章分享
- 2024-11-23用shell怎么写一个开机时自动同步远程仓库的代码?-icode9专业技术文章分享
- 2024-11-23webman可以同步自己的仓库吗?-icode9专业技术文章分享
- 2024-11-23在 Webman 中怎么判断是否有某命令进程正在运行?-icode9专业技术文章分享
- 2024-11-23如何重置new Swiper?-icode9专业技术文章分享
- 2024-11-23oss直传有什么好处?-icode9专业技术文章分享
- 2024-11-23如何将oss直传封装成一个组件在其他页面调用时都可以使用?-icode9专业技术文章分享
- 2024-11-23怎么使用laravel 11在代码里获取路由列表?-icode9专业技术文章分享
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享