• AQS简介


    AQS

    简介

    AQS的核心思想是通过一个FIFO等待队列来实现线程的阻塞和唤醒。AQS维护了一个状态,通过获取和释放状态来实现线程的同步操作。在AQS中,定义了两种队列,即Condition队列和等待队列。Condition队列主要用于支持Condition对象,而等待队列则是实现阻塞同步的关键。

    AQS的等待队列中的节点被称为Waiter。每个Waiter节点代表一个等待线程,包含了线程的相关信息。当一个线程需要等待条件或锁时,它会创建一个Waiter节点并加入到AQS的等待队列中。当条件满足或锁可用时,AQS会从等待队列中选择一个节点唤醒,使其从阻塞状态恢复到可运行状态。(说人话就是需要锁时加入队列与释放锁以后唤醒节点)

    在具体的同步工具中,比如ReentrantLock、Semaphore等,都是通过继承AQS并实现其抽象方法来实现线程的同步和协调。我认为AQS的设计是非常巧妙的,它为我们提供了一种通用的同步机制,使得我们可以更容易地构建复杂的并发工具。"

    内部结构

    互斥锁: 在互斥锁中,state通常为0表示锁是可用的,为1表示锁被占用。当线程获取锁时,会尝试将state从0修改为1,如果成功,线程获得了锁
    在这里插入图片描述
    在这里插入图片描述

    CAS

    CAS 操作通常包含以下三个参数:

    内存位置(通常是一个变量的引用)。
    预期值(当前内存位置的值)。
    新值(用来替换内存位置的值)。
    CAS 操作执行的逻辑是:

    比较内存位置的值与预期值。
    如果相等,将内存位置的值更新为新值。
    如果不相等,CAS 操作不执行更新,并返回失败。

    CAS与ABA问题

    ABA问题是指在多线程环境下,如果一个值从A变为B,然后再变回A,CAS操作会错误地认为它的值从未改变过。这可能导致意外的结果,特别是在一些需要关注数据的连续性的情况下。

    自定义一个自己的AQS

    import java.util.concurrent.locks.AbstractQueuedSynchronizer;
    
    public class CustomLock {
        // AQS成员变量
        private final Sync sync = new Sync();
    
        // 自定义同步器继承AQS
        static class Sync extends AbstractQueuedSynchronizer {
            // 在AQS中,最重要的成员变量之一,表示同步状态
            // int state;
    
            // 构造函数
            Sync() {
                setState(0); // 初始状态
            }
    
            @Override
            protected boolean tryAcquire(int acquires) {
                // 重写tryAcquire方法以获取锁
                int c = getState();
                if (c == 0) {
                    if (compareAndSetState(0, acquires)) {
                        setExclusiveOwnerThread(Thread.currentThread());
                        return true;
                    }
                }
                return false;
            }
    
            @Override
            protected boolean tryRelease(int releases) {
                // 重写tryRelease方法以释放锁
                if (Thread.currentThread() != getExclusiveOwnerThread()) {
                    throw new IllegalMonitorStateException();
                }
                int c = getState() - releases;
                if (c == 0) {
                    setExclusiveOwnerThread(null);
                }
                setState(c);
                return true;
            }
    
            // 其他自定义方法可以根据需要添加
        }
    
        public void lock() {
            sync.acquire(1);
        }
    
        public void unlock() {
            sync.release(1);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    AQS核心

    假设多线程环境,第一个持有锁,其他的CAS操作失败阻塞住,以此放到AQS同步队列中
    在这里插入图片描述
    线程0释放锁,线程1被唤醒获取锁
    在这里插入图片描述
    队头元素出队(就是null结点)
    在这里插入图片描述

    AQS源码

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

  • 相关阅读:
    Java面试(基础篇)——解构Java常见的基础面试题 & 结合Java源码分析
    (十五)VBA常用基础知识:正则表达式的使用
    java压缩pdf体积,图片体积
    Fooocus框架代码分析
    PyTorch神经网络-激励函数
    飞致云开源社区月度动态报告(2023年9月)
    SVC服务的发现
    linux 系统下文本编辑常用的命令
    智能AI系统ChatGPT网站源码+支持OpenAI DALL-E3文生图+支持ai绘画(Midjourney)/支持GPT全模型+国内AI全模型
    【Hadoop】-HDFS的Shell操作[3]
  • 原文地址:https://blog.csdn.net/weixin_43914278/article/details/133785278