JUC之AQS
文章目录
- 一、AQS核心概念与设计哲学
- 1.1 AQS是什么?
- 1.2 AQS的核心数据结构
- 二、AQS核心原理深度解析
- 2.1 同步状态【state】管理
- 2.2 CLH队列的工作原理
- 2.3 模板方法模式
- 三、AQS两种同步模式
- 3.1 独占模式(Exclusive)
- 3.1.1 独占模式获取资源
- 3.1.2 关键辅助方法解析
- 3.1.3 独占模式释放资源
- 3.2 共享模式(Shared)
- 3.2.1 共享模式获取资源
- 3.2.2 共享模式释放资源
- 四、基于AQS的实现示例
- 4.1 自定义互斥锁
- 4.2 CustomMutex使用示例
- 4.3 不可重入互斥锁(Mutex)
- 4.4 二元信号量(BinarySemaphore)
- 4.5 自定义高级同步器
- 五、AQS在JUC中的实际应用
- 5.1 ReentrantLock 中的 AQS 应用
- 5.2 CountDownLatch 中的 AQS 应用
- 六、AQS高级特性
- 6.1 条件变量(Condition)的实现
- 6.2 Condition示例
- 七、AQS性能优化与最佳实践
- 7.1 最佳实践总结
- 7.2 使用经验
- ❌ 避免陷阱
- 八、总结AQS
一、AQS核心概念与设计哲学
1.1 AQS是什么?
AbstractQueuedSynchronizer(AQS)是 Java 并发包 (java.util.concurrent.locks
) 中的核心框架,用于构建锁和其他同步器的基础。它提供了一个基于 FIFO 等待队列的同步器框架,JUC 中的大多数同步工具如 ReentrantLock、Semaphore、CountDownLatch 都是基于 AQS 构建的。
核心设计思想:
- 状态管理:使用一个 volatile int 类型的 state 变量表示同步状态
- 队列管理:通过内置的 FIFO 队列管理获取同步状态失败的线程
- 模板方法:通过模板方法模式,子类通过继承并实现指定方法管理同步状态
1.2 AQS的核心数据结构
// AQS 简化核心结构
public abstract class AbstractQueuedSynchronizer {// 同步状态,volatile保证可见性private volatile int state;// CLH队列头节点private transient volatile Node head;// CLH队列尾节点private transient volatile Node tail;// CLH队列节点定义static final class Node {// 节点模式:共享、独占static final Node SHARED = new Node();static final Node EXCLUSIVE = null;// 等待状态volatile int waitStatus;// 前驱和后继节点volatile Node prev;volatile Node next;// 节点关联的线程volatile Thread thread;}
}
二、AQS核心原理深度解析
组件 | 说明 |
---|---|
state | int 类型,表示同步状态。由 volatile 修饰,保证可见性。 |
head / tail | 指向同步队列的头节点和尾节点。 |
Node | 队列中的节点,封装等待线程及其等待状态。 |
CLH 队列变体 | AQS 使用的是 CLH 锁队列的变体,用于管理等待线程。 |
2.1 同步状态【state】管理
AQS 使用一个整型的 state 来表示同步状态,不同的子类对其有不同的解释:
- ReentrantLock:state 表示锁的重入次数(0表示未锁定,>0表示重入次数)
- Semaphore:state 表示可用的许可数量
- CountDownLatch:state 表示计数器值
- ReentrantReadWriteLock:高16位表示读锁数量,低16位表示写锁重入次数
2.2 CLH队列的工作原理
AQS 使用 CLH 变体的双向队列来管理等待线程。CLH 队列是一个 FIFO 队列,具有以下特性:
- 公平性:保证等待时间最长的线程最先获取锁
- 高效性:通过前驱节点的状态来减少不必要的线程唤醒
- 可扩展性:支持大量线程的排队管理
node的节点结构
static final class Node {volatile int waitStatus; // 等待状态volatile Node prev; // 前驱节点volatile Node next; // 后继节点volatile Thread thread; // 关联的线程Node nextWaiter; // 下一个等待节点(用于条件队列)
}
等待状态的值
状态 | 值 | 含义 |
---|---|---|
SIGNAL | -1 | 当前节点的后继节点已被阻塞,需要当前节点释放时唤醒它。 |
CANCELLED | 1 | 线程已取消(如中断或超时)。 |
CONDITION | -2 | 节点在条件队列中。 |
PROPAGATE | -3 | 共享模式下,释放操作应传播到后续节点。 |
同步队列结构
说明:队列为双向链表,head
是虚拟头节点(不关联线程),tail
指向最后一个真实节点。
// CLH队列操作的核心方法
private Node addWaiter(Node mode) {// 创建新节点,包含当前线程和模式(独占/共享)Node node = new Node(Thread.currentThread(), mode);// 快速尝试添加到队列尾部Node pred = tail;if (pred != null) {node.prev = pred;if (compareAndSetTail(pred, node)) {pred.next = node;return node;}}// 如果快速添加失败,使用完整入队流程enq(node);return node;
}private Node enq(final Node node) {for (;;) { // 自旋直到成功入队Node t = tail;if (t == null) { // 队列为空,需要初始化if (compareAndSetHead(new Node())) // 设置哑节点tail = head;} else {node.prev = t;if (compareAndSetTail(t, node)) {t.next = node;return t;}}}
}
2.3 模板方法模式
AQS 使用模板方法模式,子类需要实现以下关键方法:
public abstract class AbstractQueuedSynchronizer {// 尝试获取独占锁,需要子类实现protected boolean tryAcquire(int arg) {throw new UnsupportedOperationException();}// 尝试释放独占锁,需要子类实现protected boolean tryRelease(int arg) {throw new UnsupportedOperationException();}// 尝试获取共享锁,需要子类实现protected int tryAcquireShared(int arg) {throw new UnsupportedOperationException();}// 尝试释放共享锁,需要子类实现protected boolean tryReleaseShared(int arg) {throw new UnsupportedOperationException();}// 判断是否独占模式,需要子类实现protected boolean isHeldExclusively() {throw new UnsupportedOperationException();}
}
三、AQS两种同步模式
3.1 独占模式(Exclusive)
一次只有一个线程可以获取同步状态,如 ReentrantLock。
// 独占模式获取同步状态的核心流程
public final void acquire(int arg) {if (!tryAcquire(arg) && // 首先尝试获取acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // 失败则加入队列selfInterrupt(); // 如果等待过程中被中断,重新设置中断标志
}// 独占模式获取同步状态的详细流程
public final void acquire(int arg) {if (!tryAcquire(arg)) { // 尝试获取锁失败Node node = addWaiter(Node.EXCLUSIVE); // 创建独占模式节点并入队boolean interrupted = false;for (;;) { // 自旋final Node p = node.predecessor(); // 获取前驱节点if (p == head && tryAcquire(arg)) { // 如果前驱是头节点且获取成功setHead(node); // 将自己设为头节点p.next = null; // 帮助GCreturn;}if (shouldParkAfterFailedAcquire(p, node) && // 检查是否需要parkparkAndCheckInterrupt()) // park并检查中断interrupted = true;}}
}
独占模式获取锁流程
独占模式释放锁
特点:同一时间只有一个线程能获取同步资源(如ReentrantLock
的独占锁)。
核心流程
:线程获取资源→成功则执行→失败则加入等待队列并阻塞→资源释放后唤醒队列中的下一个线程。
3.1.1 独占模式获取资源
acquire (int arg)
acquire
是 AQS 提供的模板方法,子类无需重写,直接调用即可。流程如下:
-
调用子类重写的tryAcquire(arg)
尝试获取资源:
- 成功:直接返回,线程继续执行;
- 失败:执行后续步骤。
-
调用
addWaiter(Node.EXCLUSIVE)
创建独占模式的Node
节点,并加入队列尾部; -
调用
acquireQueued(node, arg)
让节点在队列中自旋等待,直到获取资源或被取消。
简化后的核心代码:
public final void acquire(int arg) {// 1. 尝试获取资源,失败则加入队列并自旋等待if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) {// 若自旋过程中被中断,标记当前线程需要中断selfInterrupt();}
}
3.1.2 关键辅助方法解析
- tryAcquire(int arg)
抽象方法,由子类实现,定义 “如何获取资源” 的逻辑。AQS 中默认抛出UnsupportedOperationException
,子类必须重写(如ReentrantLock
)。示例(非公平锁的tryAcquire
实现)
protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();// 1. 若状态为0(无锁),尝试CAS获取锁if (c == 0) {if (compareAndSetState(0, acquires)) {// 2. 标记当前线程为锁持有者setExclusiveOwnerThread(current);return true;}}// 3. 若当前线程已持有锁(重入),增加state计数else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0) // 防止溢出throw new Error("Maximum lock count exceeded");setState(nextc);return true;}// 4. 其他情况,获取失败return false;
}
- addWaiter(Node mode)
创建节点并加入队列尾部(CAS 保证线程安全),流程如下:
private Node addWaiter(Node mode) {// 1. 创建当前线程的Node节点(mode为EXCLUSIVE或SHARED)Node node = new Node(Thread.currentThread(), mode);Node pred = tail;// 2. 若队列不为空,直接尝试CAS将节点加入尾部if (pred != null) {node.prev = pred;if (compareAndSetTail(pred, node)) {pred.next = node;return node;}}// 3. 队列为空或CAS失败,通过enq方法自旋加入队列enq(node);return node;
}// 自旋CAS加入队列,确保节点被成功添加
private Node enq(final Node node) {for (;;) {Node t = tail;if (t == null) { // 队列空,初始化头节点(虚拟节点)if (compareAndSetHead(new Node()))tail = head;} else { // 队列非空,CAS添加到尾部node.prev = t;if (compareAndSetTail(t, node)) {t.next = node;return t;}}}
}
- acquireQueued(final Node node, int arg)
节点在队列中自旋等待,核心逻辑是 “前驱节点是头节点时,再次尝试获取资源;否则阻塞当前线程”,流程如下:
final boolean acquireQueued(final Node node, int arg) {boolean failed = true;try {boolean interrupted = false;// 自旋循环,直到获取资源或被取消for (;;) {final Node p = node.predecessor(); // 获取前驱节点// 1. 若前驱是头节点,尝试获取资源if (p == head && tryAcquire(arg)) {setHead(node); // 2. 获取成功,将当前节点设为头节点(原头节点被GC回收)p.next = null; // 3. 断开原头节点的引用,避免内存泄漏failed = false;return interrupted; // 4. 返回是否被中断过}// 5. 若获取失败,判断是否需要阻塞当前线程if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt()) {// 6. 若线程被中断,标记interrupted为trueinterrupted = true;}}} finally {if (failed) {// 7. 若获取资源失败且发生异常,取消当前节点cancelAcquire(node);}}
}
其中,shouldParkAfterFailedAcquire
方法用于设置前驱节点的状态为SIGNAL
,确保后续能被唤醒;parkAndCheckInterrupt
方法通过LockSupport.park(this)
阻塞当前线程,并返回是否被中断。
3.1.3 独占模式释放资源
release (int arg)
release
也是模板方法,用于释放资源并唤醒队列中的下一个线程,流程如下:
-
调用子类重写的tryRelease(arg)
尝试释放资源:
- 成功:执行后续步骤;
- 失败:直接返回
false
。
-
唤醒队列中的下一个节点(若存在)。
简化后的核心代码
public final boolean release(int arg) {// 1. 尝试释放资源if (tryRelease(arg)) {Node h = head;// 2. 若头节点不为空且状态不是初始状态,唤醒下一个节点if (h != null && h.waitStatus != 0) {unparkSuccessor(h);}return true;}return false;
}
tryRelease 示例(ReentrantLock 实现):
protected final boolean tryRelease(int releases) {int c = getState() - releases;// 1. 只有锁持有者才能释放锁if (Thread.currentThread() != getExclusiveOwnerThread())throw new IllegalMonitorStateException();boolean free = false;// 2. 若state减为0,说明锁已完全释放if (c == 0) {free = true;setExclusiveOwnerThread(null); // 清除锁持有者}setState(c); // 更新状态return free;
}
unparkSuccessor 方法:唤醒头节点的后继节点(跳过CANCELLED
状态的节点),核心逻辑是通过LockSupport.unpark(s.thread)
唤醒线程。
3.2 共享模式(Shared)
特点:同一时间多个线程可同时获取同步资源(如Semaphore
、CountDownLatch
)。
核心流程与独占模式类似,但差异在于:
- 共享模式下,线程获取资源成功后,会继续唤醒后续等待的共享线程(如
CountDownLatch
的countDown
后,所有等待线程被唤醒); - 核心方法为
acquireShared(int arg)
(获取资源)和releaseShared(int arg)
(释放资源)。
// 共享模式获取同步状态
public final void acquireShared(int arg) {if (tryAcquireShared(arg) < 0) // 尝试获取doAcquireShared(arg); // 失败则加入队列
}// 共享模式获取的详细实现
private void doAcquireShared(int arg) {final Node node = addWaiter(Node.SHARED); // 创建共享模式节点boolean interrupted = false;try {for (;;) { // 自旋final Node p = node.predecessor(); // 前驱节点if (p == head) {int r = tryAcquireShared(arg); // 尝试获取共享锁if (r >= 0) { // 获取成功setHeadAndPropagate(node, r); // 设置头节点并传播p.next = null; // 帮助GCreturn;}}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())interrupted = true;}} finally {if (interrupted)selfInterrupt();}
}
3.2.1 共享模式获取资源
acquireShared (int arg)
模板方法,流程如下:
-
调用子类重写的tryAcquireShared(arg)
尝试获取资源:
- 返回值
>=0
:获取成功,返回; - 返回值
<0
:获取失败,加入队列并阻塞。
- 返回值
-
若获取失败,调用
doAcquireShared(arg)
将节点加入队列并自旋等待。
简化后的核心代码
public final void acquireShared(int arg) {if (tryAcquireShared(arg) < 0) {doAcquireShared(arg); // 加入队列并自旋}
}
tryAcquireShared 示例(Semaphore 实现)
protected int tryAcquireShared(int acquires) {for (;;) {int available = getState();int remaining = available - acquires;// 1. 若可用许可不足,或CAS修改许可失败,继续自旋if (remaining < 0 ||compareAndSetState(available, remaining)) {return remaining; // 返回剩余许可(<0表示获取失败)}}
}
3.2.2 共享模式释放资源
releaseShared (int arg)
模板方法,流程如下:
- 调用子类重写的
tryReleaseShared(arg)
尝试释放资源(CAS 确保原子性); - 若释放成功,唤醒队列中的后续共享节点。
简化后的核心代码
public final boolean releaseShared(int arg) {if (tryReleaseShared(arg)) {doReleaseShared(); // 唤醒后续节点return true;}return false;
}
tryReleaseShared 示例(Semaphore 实现)
protected final boolean tryReleaseShared(int releases) {for (;;) {int current = getState();int next = current + releases;if (next < current) // 防止溢出throw new Error("Maximum permit count exceeded");// CAS修改许可数量,成功则返回trueif (compareAndSetState(current, next))return true;}
}
四、基于AQS的实现示例
4.1 自定义互斥锁
package cn.tcmeta.aqs;import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;/*** 基于AQS的自定义互斥锁实现* 演示AQS独占模式的基本用法*/
public class CustomMutex implements Lock {private final Sync sync = new Sync();// 自定义同步器,继承AQSprivate static class Sync extends AbstractQueuedSynchronizer {// 是否被占用@Overrideprotected boolean isHeldExclusively() {return getState() == 1;}// 尝试获取锁@Overridepublic boolean tryAcquire(int acquires) {// 使用CAS操作尝试将state从0改为1if (compareAndSetState(0, 1)) {setExclusiveOwnerThread(Thread.currentThread()); // 设置独占线程return true;}return false;}// 尝试释放锁@Overrideprotected boolean tryRelease(int releases) {if (getState() == 0) throw new IllegalMonitorStateException("锁未被当前线程持有");setExclusiveOwnerThread(null); // 清除独占线程setState(0); // 释放锁return true;}// 创建条件变量Condition newCondition() {return new ConditionObject();}}// Lock接口方法实现@Overridepublic void lock() { sync.acquire(1); }@Overridepublic boolean tryLock() { return sync.tryAcquire(1); }@Overridepublic void unlock() { sync.release(1); }@Overridepublic Condition newCondition() { return sync.newCondition(); }@Overridepublic void lockInterruptibly() throws InterruptedException {sync.acquireInterruptibly(1);}@Overridepublic boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {return sync.tryAcquireNanos(1, unit.toNanos(timeout));}
}
4.2 CustomMutex使用示例
package cn.tcmeta.aqs;import java.util.concurrent.CountDownLatch;/*** AQS自定义锁使用示例*/
public class AQSExample {private final CustomMutex mutex = new CustomMutex();private int sharedResource = 0;public void demonstrateMutex() throws InterruptedException {// 创建多个线程竞争访问共享资源int threadCount = 5;CountDownLatch startLatch = new CountDownLatch(1);CountDownLatch endLatch = new CountDownLatch(threadCount);for (int i = 0; i < threadCount; i++) {final int threadId = i;new Thread(() -> {try {startLatch.await(); // 等待开始信号// 使用自定义互斥锁保护临界区mutex.lock();try {System.out.println("线程 " + threadId + " 获取锁,共享资源: " + sharedResource);sharedResource++;Thread.sleep(100); // 模拟工作} finally {mutex.unlock();}} catch (InterruptedException e) {Thread.currentThread().interrupt();} finally {endLatch.countDown();}}).start();}startLatch.countDown(); // 开始所有线程endLatch.await(); // 等待所有线程完成System.out.println("最终共享资源值: " + sharedResource);}static void main(String[] args) throws InterruptedException {AQSExample example = new AQSExample();example.demonstrateMutex();}
}
4.3 不可重入互斥锁(Mutex)
package cn.tcmeta.aqs;import java.util.concurrent.locks.AbstractQueuedSynchronizer;/*** 基于 AQS 实现的不可重入互斥锁* state = 0: 未加锁, state = 1: 已加锁*/
public class Mutex {private static class Sync extends AbstractQueuedSynchronizer {@Overrideprotected boolean tryAcquire(int acquires) {// 仅当 state 为 0 时,通过 CAS 获取锁return compareAndSetState(0, 1);}@Overrideprotected boolean tryRelease(int releases) {// 释放锁,设置 state 为 0setState(0);return true;}@Overrideprotected boolean isHeldExclusively() {return getState() == 1;}}private final Sync sync = new Sync();public void lock() {sync.acquire(1);}public void unlock() {sync.release(1);}public boolean tryLock() {return sync.tryAcquire(1);}
}
4.4 二元信号量(BinarySemaphore)
package cn.tcmeta.aqs;import java.util.concurrent.locks.AbstractQueuedSynchronizer;/*** 二元信号量:只有 0 或 1 个许可*/
public class BinarySemaphore {private static class Sync extends AbstractQueuedSynchronizer {Sync(int permits) {setState(permits); // 初始化许可数}@Overrideprotected int tryAcquireShared(int acquires) {for (;;) {int available = getState();int remaining = available - acquires;if (remaining < 0 || compareAndSetState(available, remaining)) {return remaining;}}}@Overrideprotected boolean tryReleaseShared(int releases) {for (;;) {int current = getState();int next = current + releases;if (compareAndSetState(current, next)) {return true;}}}}private final Sync sync;public BinarySemaphore(int permits) {if (permits < 0) throw new IllegalArgumentException();this.sync = new Sync(permits);}public void acquire() throws InterruptedException {sync.acquireSharedInterruptibly(1);}public void release() {sync.releaseShared(1);}
}
4.5 自定义高级同步器
支持超时等待锁
/*** 支持超时等待的自定义锁* 演示AQS高级用法*/
public class TimeoutMutex implements Lock {private final Sync sync = new Sync();private static class Sync extends AbstractQueuedSynchronizer {@Overrideprotected boolean tryAcquire(int acquires) {if (compareAndSetState(0, 1)) {setExclusiveOwnerThread(Thread.currentThread());return true;}return false;}@Overrideprotected boolean tryRelease(int releases) {if (getState() == 0) throw new IllegalMonitorStateException();setExclusiveOwnerThread(null);setState(0);return true;}// 添加超时获取方法public boolean tryAcquireNanos(int acquires, long nanosTimeout) throws InterruptedException {return tryAcquire(acquires) || doAcquireNanos(acquires, nanosTimeout);}}@Overridepublic void lock() {sync.acquire(1);}@Overridepublic boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {return sync.tryAcquireNanos(1, unit.toNanos(timeout));}// 其他方法实现...
}
五、AQS在JUC中的实际应用
5.1 ReentrantLock 中的 AQS 应用
/*** ReentrantLock中AQS应用分析*/
public class ReentrantLock implements Lock {private final Sync sync;abstract static class Sync extends AbstractQueuedSynchronizer {// 非公平锁尝试获取final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) { // 锁未被占用if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) { // 重入int nextc = c + acquires;if (nextc < 0) throw new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}@Overrideprotected final boolean tryRelease(int releases) {int c = getState() - releases;if (Thread.currentThread() != getExclusiveOwnerThread())throw new IllegalMonitorStateException();boolean free = false;if (c == 0) {free = true;setExclusiveOwnerThread(null);}setState(c);return free;}}// 非公平锁实现static final class NonfairSync extends Sync {@Overrideprotected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}}// 公平锁实现static final class FairSync extends Sync {@Overrideprotected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {if (!hasQueuedPredecessors() && // 检查是否有前驱节点(公平性)compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) { // 重入int nextc = c + acquires;if (nextc < 0) throw new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}}
}
5.2 CountDownLatch 中的 AQS 应用
/*** CountDownLatch中AQS应用分析*/
public class CountDownLatch {private static final class Sync extends AbstractQueuedSynchronizer {Sync(int count) {setState(count); // 初始化计数器}int getCount() {return getState();}// 共享模式尝试获取@Overrideprotected int tryAcquireShared(int acquires) {return (getState() == 0) ? 1 : -1;}// 共享模式尝试释放@Overrideprotected boolean tryReleaseShared(int releases) {for (;;) { // 自旋直到成功int c = getState();if (c == 0) return false; // 已经为0,不需要释放int nextc = c - 1;if (compareAndSetState(c, nextc)) // CAS更新状态return nextc == 0; // 返回是否达到0}}}private final Sync sync;public CountDownLatch(int count) {if (count < 0) throw new IllegalArgumentException("count < 0");this.sync = new Sync(count);}public void await() throws InterruptedException {sync.acquireSharedInterruptibly(1);}public void countDown() {sync.releaseShared(1);}
}
六、AQS高级特性
6.1 条件变量(Condition)的实现
AQS 内部类ConditionObject
实现了Condition
接口,提供了类似Object.wait()
/notify()
的等待 / 通知机制,但更灵活(一个锁可关联多个条件队列)
ConditionObject
是 AQS 的内部类。- 每个
Condition
对应一个条件等待队列(单向链表)。 await()
:当前线程释放锁,加入条件队列,阻塞。signal()
:将条件队列首节点转移到同步队列,等待获取锁。
示例流程:
- 线程获取锁后调用
condition.await()
,释放锁并进入条件队列; - 其他线程调用
condition.signal()
,将条件队列的节点移至主队列; - 主队列中的节点按规则竞争锁,获取锁后继续执行。
6.2 Condition示例
/*** AQS条件变量使用示例*/
public class ConditionExample {private final Lock lock = new ReentrantLock();private final Condition condition = lock.newCondition();private boolean conditionMet = false;public void awaitCondition() throws InterruptedException {lock.lock();try {while (!conditionMet) { // 条件检查,防止虚假唤醒System.out.println("条件未满足,线程进入等待...");condition.await(); // 释放锁并等待}// 条件满足,执行操作System.out.println("条件满足,继续执行...");} finally {lock.unlock();}}public void signalCondition() {lock.lock();try {conditionMet = true;System.out.println("条件已满足,唤醒等待线程...");condition.signal(); // 唤醒一个等待线程} finally {lock.unlock();}}public void signalAllCondition() {lock.lock();try {conditionMet = true;System.out.println("条件已满足,唤醒所有等待线程...");condition.signalAll(); // 唤醒所有等待线程} finally {lock.unlock();}}
}
七、AQS性能优化与最佳实践
7.1 最佳实践总结
- 正确实现模板方法:
- 确保
tryAcquire
/tryRelease
等方法的线程安全性 - 正确管理同步状态 (state)
- 确保
- 合理选择同步模式:
- 独占模式:互斥访问资源(如锁)
- 共享模式:多个线程可同时访问(如信号量)
- 避免常见陷阱:
- 正确处理中断
- 避免死锁
- 注意内存可见性
- 性能考虑:
- 减少不必要的 CAS 操作
- 合理使用自旋等待
- 考虑公平性 vs 吞吐量权衡
7.2 使用经验
✅ 正确使用
-
优先使用标准同步器:如
ReentrantLock
,避免重复造轮子。 -
钩子方法保持轻量:避免在
tryAcquire
中执行复杂逻辑。 -
正确处理中断:在
acquireQueued
中检查中断状态。 -
避免死锁:确保
tryRelease
一定能成功释放
❌ 避免陷阱
- 不要在持有锁时调用阻塞操作(如 I/O)。
- 不要重写 AQS 的模板方法(如
acquire
),只重写钩子。 - 避免在
tryRelease
中抛出异常,否则队列无法唤醒
八、总结AQS
AQS 的成功源于其分层设计思想:
- 底层:基于 CAS + volatile + LockSupport 实现无锁并发
- 中层:CLH 队列管理线程排队
- 上层:模板方法 + 钩子方法 提供扩展点
一句话总结:
- AQS 是 Java 并发的“操作系统内核”——它不直接提供服务,而是为构建锁、信号量、门闩等“进程”提供统一的调度、内存和中断机制。
AQS 是 Java 并发编程的基石,其通过状态变量(state)、FIFO 等待队列和模板方法模式,为同步工具的实现提供了统一框架。理解 AQS 的核心原理,不仅能帮助我们更好地使用 JDK 中的并发工具,还能在需要时自定义高效的同步器。
AQS 的设计体现了 “高内聚、低耦合” 的思想:将复杂的队列管理、线程阻塞 / 唤醒等通用逻辑封装在抽象类中,子类只需关注具体的同步规则。这种设计极大地降低了并发组件的开发难度,也保证了这些组件在性能和可靠性上的一致性。
✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅
往期资料:
链接: https://pan.baidu.com/s/13wJhUxSVY2pbWOgjuIzWtg 提取码: dhq8
点击获取往期资料合集
提取码: dhq8
✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅