您现在的位置是:首页 > 正文

【JUC】11.AQS

2024-02-29 11:44:29阅读 1

1. AQS是什么

AQS是指AbstractQueuedSynchronizer

AQS是用来实现锁或者其他同步器组件的公共基本部分的抽象实现,是重量级基础框架及整个JUC体系的基石,主要用于解决锁分配给“谁”的问题

整体就是一个抽象的FIFO队列来完成资源获取线程的排队工作,并通过一个int类变量表示持有锁的状态


2. AQS是JUC框架基础

在前面用到的ReentrantLock、CountDownLatch等底层都与AQS有关

Java并发大神DougLee,提出统一规范并简化了锁的实现,将其抽象出来屏蔽了同步状态管理、同步队列的管理和维护、阻塞线程排队和通知、唤醒机制等,是一切锁和同步组件实现的--------公共基础部分

在这里插入图片描述

就像这样的业务,加锁使得state修改为1,告诉其他线程有人正在使用,其他线程在等候区阻塞,有阻塞就需要排队,实现排队就必然需要队列,那么接下来谁获取锁,谁不能获取锁,这一系列规范都由AQS实现。

抢到资源的线程直接使用处理业务,抢不到资源的必然涉及一种排队等候机制。抢占资源失败的线程继续去等待(类似银行业务办理窗口都满了暂时没有受理窗口的顾客只能去候客区排队等候),但等候线程仍然保留获取锁的可能上获取锁流程仍在继续(候客区的顾客也在等着叫号,轮到了再去受理窗口办理业务)。

既然说到了排队等候机制,那么就一定会有某种队列形成,这样的队列是什么数据结构呢?

如果共享资源被占用,就需要一定的阻塞等待唤醒机制来保证锁分配。这个机制主要用的是CLH队列的变体实现的,将暂时获取不到锁的线程加入到队列中,这个队列就是AQS同步队列的抽象表现。它将要请求共享资源的线程及自身的等待状态封装成队列的结点对象(Node),通过 CAS、自以及LockSupportpark()的方式,维护state变量的状态,使并发达到同步的效果。

在这里插入图片描述


3. AQS能干嘛

public abstract class AbstractQueuedSynchronizer
    extends AbstractOwnableSynchronizer
    implements java.io.Serializable {

    private static final long serialVersionUID = 7373984972572414691L;

    static final class Node {
        /** Marker to indicate a node is waiting in shared mode */
        static final Node SHARED = new Node();
        /** Marker to indicate a node is waiting in exclusive mode */
        static final Node EXCLUSIVE = null;

        static final int CANCELLED =  1;
        static final int SIGNAL    = -1;
        static final int CONDITION = -2;

        static final int PROPAGATE = -3;

        volatile Node prev;


        volatile Node next;

        volatile Thread thread;

        Node nextWaiter;

        final boolean isShared() {
            return nextWaiter == SHARED;
        }

        final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }

        Node() {    // Used to establish initial head or SHARED marker
        }

        Node(Thread thread, Node mode) {     // Used by addWaiter
            this.nextWaiter = mode;
            this.thread = thread;
        }

        Node(Thread thread, int waitStatus) { // Used by Condition
            this.waitStatus = waitStatus;
            this.thread = thread;
        }
    }

    private transient volatile Node head;

    private transient volatile Node tail;

    private volatile int state;


    protected final int getState() {
        return state;
    }

}

AQS内部有个Node类,并有头指针和尾指针,AQS里面真正干活的是Node

AQS使用一个volatile的int类型的成员变量来表示同步状态,通过内置的FIFO队列来完成资源获取的排队工作将每条要去抢占资源的线程封装成一个Node节点来实现锁的分配,通过CAS完成对State值的修改。

在这里插入图片描述


4. AQS内部体系架构

在这里插入图片描述


4.1 AQS的int变量

AQS内部有一个state成员变量以及它的get和set方法

这个整型变量的作用是告诉其他线程是否有人在占用资源

如果没有其他线程就可以竞争获取到资源类

如果有,其他线程则需要在等候区等待资源空闲


4.2 AQS的CLH队列

在这里插入图片描述

CLH队列是一个双向节点,分别有指向该节点前面的指针和指向该节点后面的指针


4.3 Node

AQS中内部类Node可以理解为银行排队等候的凳子,等候的线程存在这个Node中

Node中有一个名为waitState成员变量,是指等待状态

static final class Node {
    //共享模式
    static final Node SHARED = new Node();
    //独占模式
    static final Node EXCLUSIVE = null;

    //线程被取消
    static final int CANCELLED =  1;
    //后续线程需要唤醒
    static final int SIGNAL    = -1;
    //等待condition唤醒
    static final int CONDITION = -2;
    //共享式同步状态获取将会无条件传播下去
    static final int PROPAGATE = -3;
	//初始为0,状态是上面几种
    volatile int waitStatus;
	//前置节点
    volatile Node prev;
	//后置节点
    volatile Node next;

    volatile Thread thread;

    Node nextWaiter;

    final boolean isShared() {
        return nextWaiter == SHARED;
    }

    final Node predecessor() throws NullPointerException {
        Node p = prev;
        if (p == null)
            throw new NullPointerException();
        else
            return p;
    }

    Node() {    // Used to establish initial head or SHARED marker
    }

    Node(Thread thread, Node mode) {     // Used by addWaiter
        this.nextWaiter = mode;
        this.thread = thread;
    }

    Node(Thread thread, int waitStatus) { // Used by Condition
        this.waitStatus = waitStatus;
        this.thread = thread;
    }
}

参考:尚硅谷2022版JUC并发编程(对标阿里P6-P7)

网站文章

  • Spring Boot 配置

    Spring Boot 配置

    借鉴springboot配置方式,更改现有工程的配置文件加载逻辑, 将Qt配置文件写成多份,主配置文件用于指定加载那个配置文件,方便客户机与服务器的多对多调试,服务器在不同网段的与分机设备调试。

    2024-02-29 11:43:59
  • 感悟线段树

    感悟线段树

    其实线段树的数据结构没什么可说的,但是怎么用好它就有得说了。具体的来说就是:首先就是有段关系了,这个是第一位的。接着就是有大小关系了,这个是第二位的。再者就是数据量大,这个是次要的。只要满足了这三个条件,就是用线段树的时候了。如何理解段呢?比如说让你统计小于200的数据有多少个。这个就是段了。至于大小就是小于200的200了。(1)1 3 2 4 5 63 563 ...

    2024-02-29 11:43:54
  • 搭建本地CDH 安装中心

    搭建思路:对于搭建本地安装中心,就要把远程的yum 源里面所有的资源 ,先下载到本地。 之后可以用Nginx,或者Apache 搭建一个web 服务,把 yum 源中相应的地址,替换成 web 服务的相对应的目录就可以了。yum 源 核心配置文件设置yum源的配置定义文件,该文件必须存放在/etc/yum.repos.d目录下,并且要以“.repo”

    2024-02-29 11:43:47
  • 详解Bootstrap glyphicons-halflings-regular.woff2 Not found

    看了好几个关于Bootstrap glyphicons-halflings-regular.woff2 Not found,的博主写的,他们都没有具体的细节。首先,出现这个问题的原因是,没有将具体的包...

    2024-02-29 11:43:17
  • (八) Usb摄像头描述符解析

    (八) Usb摄像头描述符解析

    目录 Usb摄像头描述符解析 总结 参考资料 打印设备描述符 打印配置描述符 打印接口联合体描述符 打印接口描述符 打印当前设置的额外描述符 代码解析额外的描述符 打印端点描述符 ...

    2024-02-29 11:43:08
  • signature=b818d3ee5bbba9440d887bddd6fe5b5e,Bug #1516031 “Use of MD5 in OpenStack Glance image signat...

    This have been reported by Daniel P. Berrange:"In the OpenStack Liberty release, the Glance project ...

    2024-02-29 11:43:01
  • 自动计算列宽的tabularx宏包

    自动计算列宽的tabularx宏包

    David Carlisle编写的宏包tabularx增强了标准LaTeX制表环境tabular* 的功能,它能根据表格的总宽度自动计算特定表格列的宽度。一旦计算出来,则将格式自转换为 p{某个列宽值},是个段落盒子\parbox[t]{某个列宽值}。 在tabularx宏包中,X列格式被设置成p列格式的形式,它是由参数 \tabularxcolumn定义的,并且与\parbox [t]相关

    2024-02-29 11:42:34
  • 自己动手写编译器之Tiny语言语法分析器的实现

    自己动手写编译器之Tiny语言语法分析器的实现

    接着上一篇文章介绍的Tiny语言的词法分析的实现,本文将介绍Tiny语言的语法分析器的实现。1 Tiny语言的语法下图是Tiny在BNF中的文法, 文法的定义可以看出,INNY语言有以下特点: 1 程序共有5中语句:if语句,repea语句,read语句,write语法和assign语句。 2 if语句以end作为结束符号,if语句和repeat语句允许语句序列作为主体。 3 输

    2024-02-29 11:42:27
  • Spring中开启事务的第三种:注解配置

    Spring中开启事务的第三种:注解配置 步骤 导包 spring-aop-4.3.8.RELEASE.jar spring-aspects-4.3.8.RELEASE.jar 联盟包:com.spr...

    2024-02-29 11:42:19
  • 关于typeScript中接口的一些理解

    文章目录前言一、文档说明示例及疑问点疑问点:在Control类内部,是允许通过SelectableControl的实例来访问私有成员state的。证明:要证明上述理解正确,只需要在Control类内部...

    2024-02-29 11:42:11