什么是 AQS?
AQS,全称 AbstractQueuedSynchronizer,是 Java 并发包(JUC)中构建锁和其他同步组件的基石。如果你用过 ReentrantLock、CountDownLatch 或者 Semaphore,其实背后都有它的身影。作为一个抽象类,AQS 本身并不直接提供具体的锁功能,而是定义了一套通用的同步逻辑模板,让子类只需关注'如何获取资源'和'如何释放资源'。
核心设计思想
AQS 的设计非常巧妙,它主要依赖两个核心要素来管理同步状态:
- volatile int state:这个变量代表了同步状态。比如对于互斥锁,state 为 0 表示空闲,为 1 表示被占用。修改这个值的过程必须是原子性的,通常借助 CAS(Compare-And-Swap)操作完成。
- FIFO 等待队列:当线程无法立即获取资源时,会被封装成 Node 节点放入等待队列中排队。这保证了线程获取资源的公平性,避免了饥饿现象。
独占与共享模式
为了适应不同的场景,AQS 支持两种同步模式:
- 独占模式(Exclusive):同一时刻只有一个线程能执行。典型的例子就是
ReentrantLock。线程尝试获取资源时,如果失败,就进入等待队列阻塞。 - 共享模式(Shared):多个线程可以同时执行。比如
CountDownLatch的计数归零后,所有等待的线程都能继续。
在实现具体同步器时,开发者只需要重写几个关键方法,比如 tryAcquire、tryRelease、tryAcquireShared 等,剩下的排队、唤醒、中断处理都由 AQS 内部统一搞定。这种设计极大地减少了重复代码,让并发工具类的开发变得高效且规范。
实际使用中的注意点
虽然 AQS 提供了强大的能力,但在实际使用中也要注意线程安全。比如在自定义同步器时,确保对 state 的修改是原子的,并且正确处理中断信号。如果不小心忽略了这些细节,很容易导致死锁或者线程挂起无法恢复。
总的来说,AQS 是 Java 并发编程绕不开的一章。理解了它的运行机制,你对 JUC 包的理解就能从'会用'提升到'懂原理'的层面。

