AQS系列文章 | 并发编程基石:为什么需要AQS?

43 阅读4分钟

[原文链接](AQS系列文章 | 并发编程基石:为什么需要AQS?) 这是AQS系列的第一篇,本文将通过同步问题的本质、传统同步方案、AQS的定位、AQS解决的典型问题四个方面让你建立对AQS的感性认知。


一、从生活中的“排队”说起

想象你在银行办业务,假如窗口只有一个柜员,但来了10个客户。这时候可能出现两种混乱:

  1. 所有人都挤到窗口前(竞态条件):谁先抢到位置谁办业务,其他人只能干等。

  2. 柜员被重复打扰(线程不安全):客户A正在办业务,客户B却强行插队提交材料,可能导致材料混乱。

这就是多线程并发问题的缩影:
当多个线程竞争同一资源时,如何保证有序、安全地访问?


二、同步问题的本质

1. 竞态条件(Race Condition)

// 典型例子:多线程转账
publicclassBankAccount {
    privateintbalance=100// 初始余额100元
    
    // 线程不安全的转账方法
    publicvoidtransfer(int amount) {
        if (balance >= amount) {
            balance -= amount; // 问题发生在这里!
        }
    }
}

假设两个线程同时操作一个账户进行转账:

  • 线程A要转出80元,判断balance >= 80后即将扣款

  • 此时线程B抢先转出50元,余额变为50元

  • 线程A继续执行balance -= 80,导致余额变为-30元!

这就是典型的竞态条件多个线程操作共享资源的顺序不可控

2. 线程安全的核心诉求

要解决上述问题,必须实现:

  • 原子性:转账操作(判断+扣款)必须一起打包执行不可分割

  • 可见性:一个线程修改余额后,其他线程立刻看到最新值

  • 有序性:代码执行顺序不被编译器或CPU随意优化


三、传统方案:synchronized的局限

Java早期使用synchronized实现同步:

public synchronized void transfer(int amount) {
    if (balance >= amount) {
        balance -= amount;
    }
}

这把“万能钥匙”解决了问题,但存在明显缺陷:Synchronized完全由JVM调度,它是非公平锁的典型代表,不支持公平锁;只能通过wait/notifyAll实现条件等待,无法实现多条件等待;获取锁时线程阻塞直到获取到锁,期间不支持超时取消;另外它只有独占模式,不支持共享。具体对比可查看下面表格。

局限性对比表

image.png

结论:synchronized像是“傻瓜相机”,而AQS则像“专业单反”——功能更强大,但需要更多学习成本。


四、AQS的定位:JUC核心发动机

1. 什么是AQS?

  • 全称:AbstractQueuedSynchronizer(抽象队列同步器)

  • 身份java.util.concurrent.locks包中的抽象类

  • 职责:为构建锁和同步器提供基础设施(如线程排队、状态管理)

2. 为什么说它是“基石”?

  • 数据统计:JUC包中超过80%的同步工具基于AQS实现。比如常见的ReentrantLockSemaphoreCountDownLatch都是基于AQS 实现的。

image.png

  • 设计哲学:AQS将通用流程(如线程排队)与定制逻辑(如是否允许重入)分离,不同的AQS子类只需要关注自身变化的部分,复杂的且通用流程李大师已经帮我们写好了。

五、AQS解决的典型问题

1. 公平锁 vs 非公平锁

  • 非公平锁(默认)
    允许插队,吞吐量高但可能“饿死”线程。非公平的意义在于后来者线程可以先尝试获取锁。即,线程B、C正在排队等待锁,持有锁的线程A释放锁时,刚好线程D进来,线程D不是乖乖去排队而是会先尝试获取锁,但这可能会造成排队中的线程长时间获取不到锁,这就是“线程饥饿”。

  • 公平锁
    严格按队列顺序,避免饥饿。获取不到锁就乖乖去排队,严格按先来后到的顺序。

2. 共享锁的威力

以Semaphore(信号量)为例:

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

semaphore.acquire(); // 获取许可证(state减1)
// 访问共享资源...
semaphore.release(); // 释放许可证(state加1)
  • 资源控制:类似停车场剩余车位显示牌。共享锁在于它有一定量的资源,只要资源充足,后来者线程依然可以执行。

  • 灵活性:可动态调整许可证数量。


六、总结:AQS的价值

image.png AQS就像乐高积木:你不需要从零造轮子,只需组合它提供的基础模块(状态管理、线程排队),就能搭建出ReentrantLock、Semaphore等强大的同步工具。


下一篇预告
《AQS核心原理:状态与队列机制》——我们将拆解AQS内部的神秘“计数器”和“排队区”,用动画演示线程如何有序等待!

如果对你有帮助,辛苦点赞、转发支持一下~关注【BiggerBoy】公众号,获取更多技术干货!

image.png