深入浅出 AbstractQueuedSynchronizer (AQS)

news2024/9/29 0:49:38

在这里插入图片描述

文章目录

    • 什么是 AQS
    • AQS 的工作原理
      • 同步状态(state)
      • 等待队列
    • AQS 是如何让线程排队并唤醒的
    • 公平锁和非公平锁
    • AQS 的应用场景
      • ReentrantLock(可重入锁)
        • AQS 在 ReentrantLock 中的工作原理
        • 典型应用场景
      • CountDownLatch(倒计时器)
        • AQS 在 CountDownLatch 中的工作原理
        • 典型应用场景
      • Semaphore(信号量)
        • AQS 在 Semaphore 中的工作原理
        • 典型应用场景
      • CyclicBarrier(循环栅栏)
        • AQS 的相关实现原理
        • 典型应用场景

什么是 AQS

AQS 是一个用于实现线程同步的框架。假设多个线程在争抢某个资源(比如一把锁),AQS 负责决定哪个线程能够拿到资源,哪些线程需要等待,并保证在多个线程同时竞争时不会出错。

举个例子:

想象有一台游戏机,多个孩子(线程)想要玩游戏,但每次只能有一个孩子使用。其他孩子需要排队,等前面的孩子玩完之后,才能依次接着玩。AQS 就像一个 排队管理系统,负责让孩子们按顺序使用游戏机(资源)。

AQS 的工作原理

AQS 是如何管理线程竞争资源的呢?它的核心机制有两个:

  1. 同步状态(state):表示资源是否可用。
  2. 等待队列:当资源不可用时,线程进入等待队列,按顺序排队。

同步状态(state)

AQS 使用一个整数变量 state 来表示资源的状态。举个简单的例子,假设 state = 0 表示资源(例如锁)是空闲的,而 state = 1 表示资源已被占用。

当线程来获取资源时,AQS 会检查 state 是否为 0。

  • 如果是 0,说明资源可用,线程可以成功获取资源,并将 state 设置为 1,表示资源被占用了。
  • 如果 state 是 1,说明资源已经被其他线程占用了,这个线程无法直接获取资源,而是进入 等待队列

等待队列

当资源被占用时,线程会排队等候。AQS 内部维护了一个 等待队列,就像现实中的排队一样,谁先来谁先排队。

这个队列是一个 双向链表(双向链表就是每个节点都可以知道前一个和后一个节点),等待获取资源的线程被封装成队列中的节点,当资源释放时,AQS 会按照队列的顺序唤醒等待的线程,让它们尝试再次获取资源。

AQS 是如何让线程排队并唤醒的

现在让我们看看 AQS 是如何处理线程获取资源的过程。当多个线程想获取同一个资源时,AQS 会执行以下几步:

  1. 线程尝试获取资源:当一个线程想获取资源时,AQS 首先会检查资源的状态(state)。
    • 如果资源空闲(state = 0),线程成功获取资源,state 会变为 1。
    • 如果资源已被占用(state = 1),线程会进入等待队列,等待资源被释放。
  2. 等待队列的工作方式:
    • 如果线程需要等待资源(因为资源已被其他线程占用),它会被放入等待队列。这个等待队列会按照 **先进先出(FIFO)**的顺序排队,先进入队列的线程会先被唤醒。
    • 线程进入等待队列后,AQS 会让这个线程进入一种“休眠”状态,直到它被唤醒,才可以继续运行。
  3. 释放资源并唤醒下一个线程:当某个线程用完资源后,它会“释放资源”,即将 state 变回 0,表示资源可用。AQS 会检查等待队列,唤醒队列中排在最前面的线程,让它重新尝试获取资源。

举个例子:

假设有两个人(线程)A 和 B 想要玩同一台游戏机(资源),游戏机每次只能给一个人玩:

  • A 先到,看到游戏机空闲(state = 0),于是他拿到游戏机(state = 1)。
  • B 也来了,但发现游戏机正在被 A 玩(state = 1),于是 B 只能排队等待。
  • 当 A 玩完了,他把游戏机放回去,游戏机变为空闲状态(state = 0),这时 AQS 会通知 B:“你可以继续玩了”,B 被唤醒,成功拿到游戏机玩。

公平锁和非公平锁

AQS 支持两种排队机制:公平锁和非公平锁。

公平锁:按照队列的顺序让线程获取资源,谁先排队谁先得。就像银行排队,先来的人先办理业务。

非公平锁:新来的线程即使排在队列后面,也可以直接尝试抢资源,有时候能插队成功。这种方式可以提高性能,但可能导致一些线程长时间得不到资源。

AQS 的应用场景

AbstractQueuedSynchronizer (AQS) 是 Java 并发工具包中的核心基础,许多常用的并发控制工具都基于 AQS 实现。AQS 通过状态变量(state)和线程等待队列管理线程的同步操作。在实际开发中,AQS 主要为以下几种并发工具提供支持:

  1. ReentrantLock(可重入锁)
  2. CountDownLatch(倒计时器)
  3. Semaphore(信号量)
  4. CyclicBarrier(循环栅栏)

ReentrantLock(可重入锁)

ReentrantLock 是 Java 中非常常用的显式锁,它允许同一个线程多次获取同一把锁,而不会出现死锁问题。也就是说,线程可以“重入”该锁(同一线程多次持有)。这个锁可以选择 公平锁非公平锁,确保不同线程对锁的竞争方式。

AQS 在 ReentrantLock 中的工作原理

AQS 通过 state 来表示锁的持有状态,state = 0 表示锁是空闲的,state > 0 表示锁已被占用。

当线程尝试获取锁时,AQS 会检查当前 state 是否为 0。

  • 如果锁空闲,线程能够成功获取锁,并且 state 变为 1。
  • 如果锁已经被占用,线程会进入 AQS 的等待队列,等待锁被释放。

当同一个线程多次获取锁时,AQS 会将 state 增加(重入锁的概念)。当线程释放锁时,state 递减,直到 state = 0,锁才真正释放,其他等待的线程才有机会获取锁。

典型应用场景

控制对共享资源的独占访问:例如在多线程环境中,确保同一时刻只有一个线程可以对共享数据(如某个对象或文件)进行修改,避免线程竞争造成的数据不一致或资源冲突。

Lock lock = new ReentrantLock();

lock.lock();
try {
    // 临界区代码,只能有一个线程访问
} finally {
    lock.unlock();
}

CountDownLatch(倒计时器)

CountDownLatch 是一种同步工具,允许一个或多个线程等待其他线程完成某些操作后再继续执行。例如,你可以让主线程等待所有工作线程执行完任务后再继续工作。CountDownLatch 内部依赖 AQS 来管理线程的等待和唤醒。

AQS 在 CountDownLatch 中的工作原理

AQS 使用 state 来表示倒计时的初始值。例如,如果你设置 CountDownLatch 为 3,state 就初始为 3。

当某个线程调用 countDown() 时,state 会减少 1。每个线程完成任务时都调用 countDown(),表示任务的完成。

state 减到 0 时,所有在 await() 方法上等待的线程都会被唤醒,并且可以继续执行。

典型应用场景

协调多个线程并发执行:例如,当多个线程并行处理不同任务,主线程需要等待所有子任务都完成后才能继续。你可以使用 CountDownLatch 来实现这一点。

服务启动顺序管理:在分布式系统中,某些模块可能需要等待其他模块先启动,确保它们依赖的服务已准备好。

CountDownLatch latch = new CountDownLatch(3);

for (int i = 0; i < 3; i++) {
    new Thread(() -> {
        // 执行任务
        latch.countDown();  // 任务完成,倒计时减 1
    }).start();
}

latch.await();  // 主线程等待,直到倒计时为 0
System.out.println("所有任务已完成");

Semaphore(信号量)

Semaphore 是一种限制多个线程并发访问资源的工具,它通过 AQS 来管理可以同时访问资源的线程数量。Semaphore 非常适合控制对有限资源的访问,比如数据库连接池、线程池等。

AQS 在 Semaphore 中的工作原理

Semaphore 通过 AQS 的 state 来表示剩余的可用资源数量(即许可数)。初始的 state 值表示信号量的许可数(允许多少线程同时访问资源)。

当线程调用 acquire() 方法时,AQS 会检查 state 是否大于 0:

  • 如果 state > 0,线程可以成功获取资源,state 减少。
  • 如果 state = 0,线程进入等待队列,等待其他线程释放资源(即 release())。

当线程调用 release() 释放资源时,state 增加,唤醒等待的线程来获取资源。

典型应用场景

限流和流量控制:在并发系统中,Semaphore 常用于限制同时访问某个服务或资源的线程数,防止系统过载。例如,限制同时执行的数据库查询数量,以避免过多并发请求导致服务器压力过大。

连接池管理:比如控制对数据库连接池的访问,确保不超过最大连接数。

Semaphore semaphore = new Semaphore(3);  // 允许最多 3 个线程同时访问

for (int i = 0; i < 5; i++) {
    new Thread(() -> {
        try {
            semaphore.acquire();  // 获取许可
            // 访问共享资源
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release();  // 释放许可
        }
    }).start();
}

CyclicBarrier(循环栅栏)

CyclicBarrier 是一种允许一组线程相互等待,直到所有线程都到达某个屏障后才继续执行的工具。与 CountDownLatch 不同,CyclicBarrier 可以重复使用,适合用于需要多轮次的同步操作场景。

AQS 的相关实现原理

尽管 CyclicBarrier 并没有直接使用 AQS 实现,但是它和 AQS 的等待机制类似。多个线程在调用 await() 时,会等待其他线程到达同一屏障点。当所有线程都到达屏障时,才能继续往下执行下一步操作。

典型应用场景

并行计算任务中的同步点:多个线程分工合作处理一个大任务,每个线程负责一部分任务。当所有线程都处理完各自的部分后,需要在某个同步点上汇总数据,并继续进行下一步工作。

多人游戏同步:在网络游戏中,多个玩家同时进行某一阶段游戏,所有玩家到达某个阶段的同步点后才能进入下一阶段。

CyclicBarrier barrier = new CyclicBarrier(3, () -> {
    System.out.println("所有线程到达屏障,继续执行...");
});

for (int i = 0; i < 3; i++) {
    new Thread(() -> {
        System.out.println(Thread.currentThread().getName() + " 到达屏障");
        try {
            barrier.await();  // 等待其他线程
        } catch (InterruptedException | BrokenBarrierException e) {
            e.printStackTrace();
        }
    }).start();
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2168240.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Django技术开发的酒店信息管理系统,包括员工用户功能和管理员用户功能两部分

项目摘要 该项目是基于Django技术开发的一套酒店管理系统&#xff0c;系统应用浏览器/服务期&#xff08;Browser/Server&#xff09;架构。系统主要包括员工用户功能和管理员用户功能两部分。开发员工信息管理、顾客信息管理、会员信息管理、停车场信息管理、餐厅信息管理、客…

HTML5+CSS3小实例:立方体控件的登录表单

实例:立方体控件的登录表单 技术栈:HTML+CSS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial…

【算法篇】二叉树类(1)(笔记)

目录 一、认识二叉树 1. 二叉树的种类 &#xff08;1&#xff09;满二叉树 &#xff08;2&#xff09;完全二叉树 &#xff08;3&#xff09;二叉搜索树 &#xff08;4&#xff09;平衡二叉搜索树 2. 二叉树的存储方式 3. 二叉树的遍历方式 4. 二叉树的定义 二、Leet…

(done) 使用泰勒展开证明欧拉公式

问问神奇的 GPT&#xff0c;how to prove euler formula? 一个答案如下&#xff1a;

华硕NUC亮相工博会,解锁工业AI PC解决方案

2024年9月24日至28日&#xff0c;中国国际工业博览会于上海国家会展中心盛大举行&#xff0c;华硕智能物联网展台位于展馆6.1H E183展位&#xff0c;在展位上华硕向大众展示了智能AI、物联网设备、华硕NUC等解决方案及IoT硬件产品&#xff0c;吸引了众多专业观众驻足交流和体验…

线程池的执行流程和配置参数总结

一、线程池的执行流程总结 提交线程任务&#xff1b;如果线程池中存在空闲线程&#xff0c;则分配一个空闲线程给任务&#xff0c;执行线程任务&#xff1b;线程池中不存在空闲线程&#xff0c;则线程池会判断当前线程数是否超过核心线程数&#xff08;corePoolSize&#xff09…

EfficientViT(2023CVPR):具有级联组注意力的内存高效视觉Transformer!

EfficientViT: Memory Efficient Vision Transformer with Cascaded Group Attention EfficientViT: 具有级联组注意力的内存高效视觉Transformer 万文长字&#xff0c;请耐心观看~ 论文地址&#xff1a; https://arxiv.org/abs/2305.07027 代码地址&#xff1a; Cream/Effici…

计算机毕业设计 饮食营养管理信息系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

《强化学习的数学原理》(2024春)_西湖大学赵世钰 Ch9 策略梯度方法 -9.3.1

之前看了 2 次视频&#xff0c;公式有点多&#xff0c; 还是没整理出来。 这个版本是以下步骤后的版本 基本把相关的核心论文过了一遍&#xff0c;代码整理了部分 PDF 资料 整理 v3 链接 视频 链接 习题 策略梯度方法需要估计值 函数近似&#xff1a; 状态/动作 价值、策略 参…

C++初阶:STL详解(四)——vector迭代器失效问题

✨✨小新课堂开课了&#xff0c;欢迎欢迎~✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C&#xff1a;由浅入深篇 小新的主页&#xff1a;编程版小新-CSDN博客 一&#xff1a;迭代器失效的本质 迭代器的主…

VulnStack-红日靶机(二)

红日靶机二 环境搭建 只需要把虚拟机的 host-only&#xff08;仅主机&#xff09;网卡改为 10.10.10.0 网段&#xff0c;如下配置 把 NAT 网卡&#xff0c;改为 192.168.96.0 网段&#xff0c;如下 首先恢复到 v1.3 快照 让后点击放弃&#xff0c;放弃后再开机&#xff0c;用…

Shopify独立站运营必知必会:选品与防封技巧

独立站和第三方平台是目前最常见的跨境电商销售模式&#xff0c;相比于第三方平台&#xff0c;独立站的商家可以自己建站&#xff0c;自行决定运营模式和营销手段等策略&#xff0c;尤其是在准入门槛上&#xff0c;难度会更低&#xff0c;这些特点吸引了不少商家选择独立站开店…

电动车、电单车入梯数据集电动车进电梯检测识别(代码+教程+数据集)

数据集介绍 共有 5347 张图像和一一对应的标注文件 标注文件格式提供了两种&#xff0c;包括VOC格式的xml文件和YOLO格式的txt文件。 标注的对象共有以下几种&#xff1a; [‘Electric-bicycle’] 标注框的数量信息如下&#xff1a;&#xff08;标注时一般是用英文标的&am…

使用shardingsphere实现mysql数据库分片

在大数据时代&#xff0c;随着业务数据量的不断增长&#xff0c;单一的数据库往往难以承载大规模的数据处理需求。数据库分片&#xff08;Sharding&#xff09;是一种有效的数据库扩展技术&#xff0c;通过将数据分布到多个数据库实例上&#xff0c;提高系统的性能和可扩展性。…

图解Lamda使用场景

1.参考如下文章&#xff0c;讲的挺好的 深入浅出 C Lambda表达式&#xff1a;语法、特点和应用 &#xff08;请注意&#xff1a;此链接是本章节的原文&#xff09; 2. 什么是 Lambda表达式&#xff08;截取以上参考文章&#xff09; Lambda表达式是一种在被调用的位置或作为…

每日OJ题_牛客_NC40链表相加(二)_链表+高精度加法_C++_Java

目录 牛客_NC40链表相加&#xff08;二&#xff09;_链表高精度加法 题目解析 C代码 Java代码 牛客_NC40链表相加&#xff08;二&#xff09;_链表高精度加法 链表相加(二)_牛客题霸_牛客网 题目解析 模拟⾼精度加法的过程&#xff0c;只不过是在链表中模拟。 C代码 /*…

107.WEB渗透测试-信息收集-FOFA语法(7)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;106.WEB渗透测试-信息收集-FOFA语法&#xff08;6&#xff09; 密码文件&#xff1a; 语…

MFC设置特定控件字体大小和背景颜色

MFC设置特定控件字体大小和背景颜色 初始化函数里 m_editFont.CreatePointFont(580 , _T("宋体"));m_ctrlEdit.SetFont(&m_editFont);重写消息 HBRUSH CMFCTESTDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) {HBRUSH hbr CDialogEx::OnCtlColor(pDC,…

Calcite第一课

Calcite 是什么&#xff1f; 2024 年 9 月&#xff0c;最新版本 1.37.0 。前面三节我们先不看任何的源码&#xff0c;只从背景、介绍、概念、原理层面入手&#xff0c;作为深入学习和源码分析的预备。 如果用一句话形容 Calcite&#xff0c;Calcite 是一个用于优化异构数据源的…

最全测评!分享7款超好用的AI论文润色网站

在当前的学术写作领域&#xff0c;AI论文润色工具已经成为提升论文质量和效率的重要助手。以下是七款超好用的AI论文润色网站&#xff0c;其中特别推荐千笔-AIPassPaper。 一、千笔-AIPassPaper 是一款集论文大纲生成、内容填充、文献引用、查重修改于一体的全方位论文写作平…