AbstractQueuedSynchronizer概述
AbstractQueuedSynchronizer 是一个用于在竞争资源(如多线程)时使用的同步器,它内部使用了一个int类型的字段status表示需要同步的资源状态, 并基于一个先进先出(FIFO)的等待队列,队列中的每个节点表示要获取资源的线程
工作流程
同步器主要是用于控制资源的获取以及释放,它可以用于独占模式和共享模式,这里我们以独占模式为例
在获取和释放资源时,我们需要实现自己的尝试获取和尝试释放的方法,利用
status字段来控制成功与否
获取资源
// 在独占模式下尝试获取资源
protected boolean tryAcquire(int arg) {
// 尝试获取资源与释放资源都是依靠 status 来实现具体的逻辑
// 可以基于 status 与 arg 字段来实现此方法 (我们可以赋予status任何意义来实现逻辑)
}
获取资源的源码如下(独占模式)
首先尝试获取资源,如果成功直接返回,进行后续流程
失败则创建一个新节点,将其添加到链表尾部(如果链表为空,则先创建一个空的表头再添加)
之后判断当前节点前一个节点是不是头结点,如果是则再次尝试获取资源,成功则将当前节点置为头节点,进行获取资源后的流程
如果当前节点前一个节点不是头结点,那么将当前节点中的线程阻塞(阻塞前务必将其前一节点状态改为signal),等待被唤醒
唤醒后跳转到第3步
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
释放资源
// 在独占模式下尝试释放资源
protected boolean tryRelease(int arg) {
// 尝试获取资源与释放资源都是依靠 status 来实现具体的逻辑
// 可以基于 status 与 arg 字段来实现此方法 (我们可以赋予status任何意义来实现逻辑)
}
释放资源的源码如下(独占模式) 1.首先尝试释放资源 2.成功后判断,如果头结点不为null,同时其状态不是初始0值(需要有后继节点更改其状态),那么将当前节点状态置为0,同时唤醒下一节点中线程
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
共享模式与独占模式基本相同
区别主要在于此方法,当线程被唤醒后获取资源,如果成功且返回值>0,则会继续唤醒后续线程 返回负数:失败 返回0:成功,但是其他线程无法再获取资源 返回正数:成功,其他线程可能继续获取资源(需要尝试后知道)
protected int tryAcquireShared(int arg) {
// todo
}
下面举一个《Java并发编程实战》中的二元闭锁例子来说明AQS的使用
/**
* 使用 AQS 实现的二元闭锁(所有线程都会阻塞,直到状态改变被唤醒,此时所有线程都得到执行)
* status表是开关状态,=0时关闭,=1时开启
*/
public class OneShotLatch {
private final Sync sync = new Sync();
public void signal() {
sync.releaseShared(0);
}
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(0);
}
private class Sync extends AbstractQueuedSynchronizer {
/**
* 如果闭锁是开的 (state==1),那么这个操作成功,否则失败阻塞
* @param ignored
* @return
*/
@Override
protected int tryAcquireShared(int ignored) {
return (getState() == 1) ? 1: -1;
}
/**
* 打开status状态开关,放开所有线程
* @param ignored
* @return
*/
@Override
protected boolean tryReleaseShared(int ignored) {
setState(1);
return true;
}
}
// 测试方法
public static void main(String[] args) throws Exception {
OneShotLatch oneShotLatch = new OneShotLatch();
for (int i = 0; i < 3; i++) {
new Thread(() -> {
try {
oneShotLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("completed");
}).start();
}
// 2S后唤醒
TimeUnit.SECONDS.sleep(2);
oneShotLatch.signal();
TimeUnit.SECONDS.sleep(5);
System.out.println("end");
}
}
AbstractQueuedSynchronizer概述的更多相关文章
- 30_AQS
[参考文章] https://www.jianshu.com/p/df0d7d6571de http://ifeve.com/introduce-abstractqueuedsynchronizer/ ...
- 万字长文!从底层开始带你了解并发编程,彻底帮你搞懂java锁!
线程是否要锁住同步资源 锁住 悲观锁 不锁住 乐观锁 锁住同步资源失败 线程是否要阻塞 阻塞 不阻塞自旋锁,适应性自旋锁 多个线程竞争同步资源的流程细节有没有区别 不锁住资源,多个线程只有一个能修改资 ...
- 并发编程 20—— AbstractQueuedSynchronizer 深入分析
Java并发编程实践 目录 并发编程 01—— ThreadLocal 并发编程 02—— ConcurrentHashMap 并发编程 03—— 阻塞队列和生产者-消费者模式 并发编程 04—— 闭 ...
- Java并发包源码学习之AQS框架(四)AbstractQueuedSynchronizer源码分析
经过前面几篇文章的铺垫,今天我们终于要看看AQS的庐山真面目了,建议第一次看AbstractQueuedSynchronizer 类源码的朋友可以先看下我前面几篇文章: <Java并发包源码学习 ...
- Java并发包源码学习之AQS框架(一)概述
AQS其实就是java.util.concurrent.locks.AbstractQueuedSynchronizer这个类. 阅读Java的并发包源码你会发现这个类是整个java.util.con ...
- 4.锁--Synchronizer Framework Base Class—AbstractQueuedSynchronizer介绍
1. AQS简单介绍 AQS是Java并发类库的基础.其提供了一个基于FIFO队列,可以用于构建锁或者其它相关同步装置的基础框架.该同步器(下面简称同步器)利用了一个int来表示状态,期望它可以成为实 ...
- AbstractQueuedSynchronizer 原理分析 - 独占/共享模式
1.简介 AbstractQueuedSynchronizer (抽象队列同步器,以下简称 AQS)出现在 JDK 1.5 中,由大师 Doug Lea 所创作.AQS 是很多同步器的基础框架,比如 ...
- AbstractQueuedSynchronizer AQS框架源码剖析
一.引子 Java.util.concurrent包都是Doug Lea写的,来混个眼熟 是的,就是他,提出了JSR166(Java Specification RequestsJava 规范提案), ...
- 并发系列(4)之 AbstractQueuedSynchronizer 源码分析
本文将主要讲述 AbstractQueuedSynchronizer 的内部结构和实现逻辑,在看本文之前最好先了解一下 CLH 队列锁,AbstractQueuedSynchronizer 就是根据 ...
随机推荐
- mysql 学习日记 悲观和乐观锁
理解 悲观锁就是什么事情都是需要小心翼翼,生怕弄错了出大问题, 一般情况下 "增删改" 都是有事务在进行操作的,但是 "查" 是不需要事务操作的, 但是凡事没 ...
- Elasticsearch数据建模笔记
数据建模 数据建模是创建数据模型的过程 数据模型是对真实世界进行抽象描述的一种工具和方法,实现对现实世界的映射 三个过程:概念模型=>逻辑模型=>数据模型 数据模型:结合具体的数据库,在满 ...
- Kaggle 题目 nu-cs6220-assignment-1
Kaggle题目 nu-cs6220-assignment-1 题目地址如下: https://www.kaggle.com/c/nu-cs6220-assignment-1/overview 这是个 ...
- const 详解
简单分类: 常变量 const 类型 变量名 或者 类型 const 变量名 常引用 const 类型& 引用名 ...
- 用 jQuery 实现表单验证(摘抄)——选自《锋利的jQuery》(第2版)第5章的例题 5.1.5 表单验证
5.1.5 表单验证 表单(form)作为 HTML 最重要的一个组成部分,几乎在每个网页上都有体现,例如用户提交信息.用户反馈信息和用户查询信息等,因此它是网站管理者与浏览者之间沟通的桥梁.在表单中 ...
- 手动生成WebService代理类
方式一: 手动生成WebService代理类需要把一句生成语句,如 wsdl.exe /l:cs /out:D:/ProxyServices.cs http://localhost/WebServic ...
- 网络安全从入门到精通 (第二章-6) 后端基础PHP—表单验证
本文内容: 什么是表单? 如何创建一个表单: 接收并验证: PHP和数据库交互 1,什么事表单? 表单在网页中主要负责数据采集. 表单由三部分组成: 表单标签:这里面包含了处理表单数据所用动态脚本的U ...
- Redis入门学习(学习过程记录)
Redis(入门笔记) 学习一个大的技术点,然后顺带着就把这个技术点的面试题给学习了. 学习完一个技术后,如果面试题还不能够解答的话,只能说明学的不精,需要查漏补缺. 下一个学习的方向:Redis-非 ...
- Andorid 添加MenuPopup
- Spring WebFlux 入门
1. WebFlux介绍 Spring WebFlux 是 Spring Framework 5.0中引入的新的响应式web框架.与Spring MVC不同,它不需要Servlet API,是完全异步 ...