AbstractQueuedSynchronizer之AQS

简介: AbstractQueuedSynchronizer之AQS

AbstractQueuedSynchronizer(AQS

概述

AbstractQueuedSynchronizer(简称AQS)是Java中锁和同步器的基础框架,大多数的锁和同步器都是通过继承AQS来实现的。AQS提供了一个灵活的框架,使得开发者可以根据自己的需求来实现各种锁和同步器。本文将介绍AQS的基本原理和实现细节。

基本原理

AQS维护了一个state(状态)属性和一个等待队列。state用来表示同步状态,当state为0时表示锁没有被占用,当state不为0时表示锁已经被占用,state的含义和具体使用方法是由子类定义的。等待队列则用来存储那些请求锁或者同步器的线程。

当一个线程请求锁或同步器时,如果此时state为0,则表示当前线程可以获得锁或同步器,此时会将state设置为1,表示当前锁或同步器已经被占用了。如果此时state不为0,则表示此时锁或同步器正在被其他线程占用,此时当前线程会被加入到等待队列中,等待其他线程释放锁或同步器。

当其他线程释放了锁或同步器时,会唤醒等待队列中的一个线程,使其重新尝试获取锁或同步器。如果此时该线程又成功获取了锁或同步器,则该线程会从等待队列中移除。

实现细节

等待队列

AQS的等待队列是一个双向链表,每个节点表示一个等待线程(或者称为Node),Node继承自AbstractQueuedSynchronizer。下面是Node的定义:

static final class Node {
    // 共享模式
    static final Node SHARED = new Node();
    // 独占模式
    static final Node EXCLUSIVE = null;
    // waitStatus的值表示当前节点需要等待的状态
    static final int CANCELLED =  1;
    static final int SIGNAL    = -1;
    static final int CONDITION = -2;
    static final int PROPAGATE = -3;
    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() {
    }
    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;
    }
}

Node节点有以下属性:

  • waitStatus:表示节点的状态,可以是以下值:
  • CANCELLED:表示节点已经取消。
  • SIGNAL:表示在释放同步器或者锁时需要唤醒该节点。
  • CONDITION:表示节点在等待Condition时被阻塞。
  • PROPAGATE:表示共享模式下下一个节点需要唤醒。
  • prev:表示当前节点的前一个节点。
  • next:表示当前节点的后一个节点。
  • thread:表示当前节点所对应的线程。
  • nextWaiter:表示下一个等待节点。

等待队列的头节点是一个哑节点,不表示任何一个等待线程。当等待队列不为空时,队首节点表示正在占用同步器或者锁的线程,队列中剩下的节点表示正在等待获取同步器或者锁的线程。

等待队列的操作主要有以下几个:

  • enq(node):将一个节点加入等待队列的尾部。
  • addWaiter(mode):创建一个新的节点并加入到等待队列的尾部。mode表示该节点的模式,可以是独占模式或共享模式。
  • setHead(node):设置等待队列的头节点。
  • unparkSuccessor(node):唤醒等待队列中最近的一个还未被取消的节点。在独占模式下,需要唤醒的节点是当前节点的后继节点;在共享模式下,需要唤醒的节点是等待队列中第一个未被取消的节点。

state属性

AbstractQueuedSynchronizer中,state属性是一个volatile类型的整数,用来表示同步状态。子类可以通过修改state的值来实现自己的同步机制。

state为0时表示同步器或锁没有被占用,当state不为0时表示同步器或锁已经被占用。在独占模式下,state的值为1表示锁已经被占用,在共享模式下,state的值表示正在使用锁的线程数。

state的主要操作有以下几个:

  • getState():获取当前状态的值。
  • setState(newState):设置当前状态的值。
  • compareAndSetState(expect, update):原子性地将当前状态和expect比较,如果相等则将其设置为update,并返回true,否则返回false。

独占模式

AbstractQueuedSynchronizer中的独占模式是最常用的同步机制之一,代表了Java中的锁。

我们来看一下ReentrantLock是如何实现独占模式的。

ReentrantLock

ReentrantLock是一个可重入的互斥锁,它支持公平锁和非公平锁。ReentrantLock继承自AbstractQueuedSynchronizer,在ReentrantLock的构造方法中会调用AbstractQueuedSynchronizer的构造方法来初始化state属性和等待队列。


相关文章
|
1月前
|
缓存 Java 开发者
吃透 Spring Bean 生命周期:从源码底层到实战落地
本文深度解析Spring 6.2.3 Bean生命周期,涵盖BeanDefinition注册、实例化、属性填充、Aware回调、BeanPostProcessor前后置处理、初始化(@PostConstruct/InitializingBean/init-method)、AOP代理、单例缓存及销毁全流程,结合源码、实战示例与生产问题排查,助你彻底掌握IoC核心机制。
520 3
|
2月前
|
人工智能 测试技术 API
让大模型真正为你工作:一文读懂RAG与微调的选择逻辑
本文深入解析RAG(开卷考试)与微调(封闭特训)两大私有知识注入技术:RAG实时更新、可追溯但依赖检索质量;微调风格统一、响应快但成本高、难迭代。结合实践案例与评估方法,重点推荐2024主流“混合架构”——RAG管“说什么”,微调管“怎么说”,兼顾准确性与规范性。
466 8
|
负载均衡 Dubbo 应用服务中间件
【Dubbo 解析】Dubbo支持几种负载均衡策略?
【1月更文挑战第11天】【Dubbo 解析】Dubbo支持几种负载均衡策略?
|
11月前
|
设计模式 人工智能 安全
AQS:Java 中悲观锁的底层实现机制
AQS(AbstractQueuedSynchronizer)是Java并发包中实现同步组件的基础工具,支持锁(如ReentrantLock、ReadWriteLock)和线程同步工具类(如CountDownLatch、Semaphore)等。Doug Lea设计AQS旨在抽象基础同步操作,简化同步组件构建。 使用AQS需实现`tryAcquire(int arg)`和`tryRelease(int arg)`方法以获取和释放资源,共享模式还需实现`tryAcquireShared(int arg)`和`tryReleaseShared(int arg)`。
520 32
AQS:Java 中悲观锁的底层实现机制
|
缓存 NoSQL Java
避免缓存失效的三大杀手:缓存击穿、穿透与雪崩的解决方案
避免缓存失效的三大杀手:缓存击穿、穿透与雪崩的解决方案
1901 0
|
存储 缓存 Java
HashMap源码剖析-put流程
更好地掌握 `HashMap` 的内部实现原理,提高编写高效代码的能力。掌握这些原理不仅有助于优化性能,还可以帮助解决实际开发中的问题。
525 13
|
缓存 算法 Java
这些年背过的面试题——JVM篇
本文是技术人面试系列JVM篇,面试中关于JVM都需要了解哪些基础?一文带你详细了解,欢迎收藏!
|
XML Java Maven
Springboot Starter 是如何工作的?
Springboot Starter 是 Springboot 项目的一部分,简化了依赖管理和自动配置,通过 Maven 或 Gradle 引入相关依赖并自动配置应用程序。其核心特性包括依赖管理、自动配置及条件注解。Starter 的设计思维体现了模块化、约定优于配置、依赖注入等原则,提高了开发效率,但也存在调试复杂、过度依赖等问题。
765 3
|
安全 程序员 编译器
C++程序中的基类与派生类转换
C++程序中的基类与派生类转换
325 1
|
存储 关系型数据库 MySQL
【高频】什么是索引的下推和覆盖
【高频】什么是索引的下推和覆盖
943 2