🧑 博主简介:优快云博客专家、全栈领域优质创作者、高级开发工程师、高级信息系统项目管理师、系统架构师,10年以上多种混合语言开发经验,从事DICOM医学影像开发领域多年,熟悉DICOM协议及其应用开发技术。我的技能涵盖了多种编程语言和技术框架:作为高级C/C++与C#开发工程师,我擅长Windows系统下的.NET及C++开发技术,尤其精通MFC、DLL动态链接库、WinForm、WPF、Windows服务、WebAPI及.NET Core跨平台等技术的开发工作。此外,由于项目需要,也熟悉Java开发,并利用业余时间学习了JavaScript、Vue等前端技术,同时自学了QT开发工具,对Python也有一定的了解。这使我具备了使用多种混合语言进行开发的能力。我一直坚持撰写博客文章,记录个人的学习历程,分享编程开发相关的知识与经验,旨在为编程爱好者提供帮助和支持。通过这样的方式,我希望可以与志同道合的朋友交流探讨,共同进步,在技术的世界里不断学习和成长。如果您也热衷于技术探索,愿意一起讨论最新技术趋势或解决遇到的技术难题,欢迎随时联系。让我们携手共进,在追求卓越技术的道路上越走越远。欢迎关注、学习及合作,可提供解决方案和技术支持!
技术合作请加本人wx(注明来自csdn):xt20160813
《深入浅出Java AQS:从理论到实践的全景式解析》
一、AQS核心认知:同步器世界的基石
1.1 同步器架构全景图
1.2 AQS核心组件拆解
组件名称 | 数据结构 | 作用描述 |
---|---|---|
state | volatile int | 同步状态(如锁重入次数、信号量值) |
CLH队列 | Node双向链表 | 存储等待线程的队列 |
exclusive | Thread | 独占模式下的持有线程 |
shared | - | 共享模式下的资源计数 |
二、AQS内核机制:逐行解析核心源码
2.1 关键数据结构Node
static final class Node {
volatile int waitStatus; // 等待状态(CANCELLED/SIGNAL等)
volatile Node prev; // 前驱节点
volatile Node next; // 后继节点
volatile Thread thread; // 绑定的线程
Node nextWaiter; // 共享/独占模式标识
}
2.2 acquire()方法执行流程图
2.3 核心方法源码解析(以acquire为例)
public final void acquire(int arg) {
if (!tryAcquire(arg) && // 尝试获取资源(子类实现)
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // 加入队列并自旋
selfInterrupt(); // 恢复中断状态
}
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) { // 只有前驱是头节点才尝试获取
setHead(node); // 获取成功设置为新头节点
p.next = null; // 帮助GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) && // 检查是否需要阻塞
parkAndCheckInterrupt()) // 调用LockSupport.park()
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node); // 取消获取
}
}
三、实战演练:手写可重入锁
3.1 自定义锁实现
class SimpleReentrantLock extends AbstractQueuedSynchronizer {
// 重写tryAcquire方法
@Override
protected boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState(); // 获取当前状态
if (c == 0) { // 锁未被占用
if (compareAndSetState(0, acquires)) { // CAS设置状态
setExclusiveOwnerThread(current); // 设置持有线程
return true;
}
} else if (current == getExclusiveOwnerThread()) { // 重入逻辑
setState(c + acquires); // 增加重入次数
return true;
}
return false;
}
// 重写tryRelease方法
@Override
protected 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;
}
public void lock() {
acquire(1); // 调用AQS的acquire模板方法
}
public void unlock() {
release(1); // 调用AQS的release模板方法
}
}
3.2 测试用例
public static void main(String[] args) {
SimpleReentrantLock lock = new SimpleReentrantLock();
ExecutorService executor = Executors.newFixedThreadPool(2);
Runnable task = () -> {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " 获得锁");
Thread.sleep(1000); // 模拟业务操作
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
System.out.println(Thread.currentThread().getName() + " 释放锁");
}
};
executor.submit(task);
executor.submit(task);
executor.shutdown();
}
// 输出示例:
// pool-1-thread-1 获得锁
// pool-1-thread-1 释放锁
// pool-1-thread-2 获得锁
// pool-1-thread-2 释放锁
四、AQS高级特性深度剖析
4.1 公平锁 vs 非公平锁实现差异
// 非公平锁tryAcquire实现
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires); // 直接尝试获取,不检查队列
}
// 公平锁tryAcquire实现
protected 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;
}
}
// ...重入逻辑相同
}
4.2 共享模式实现原理
// CountDownLatch.Sync内部类
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1; // 状态为0时允许获取
}
protected boolean tryReleaseShared(int releases) {
for (;;) { // CAS循环
int c = getState();
if (c == 0) return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0; // 最后一个release触发唤醒
}
}
4.3 Condition条件队列实现
public class ConditionObject implements Condition {
private transient Node firstWaiter; // 条件队列头节点
private transient Node lastWaiter; // 条件队列尾节点
public final void await() throws InterruptedException {
Node node = addConditionWaiter(); // 创建新节点加入条件队列
int savedState = fullyRelease(node); // 完全释放锁
while (!isOnSyncQueue(node)) { // 检查是否回到同步队列
LockSupport.park(this); // 挂起线程
}
acquireQueued(node, savedState); // 重新获取锁
}
public final void signal() {
Node first = firstWaiter;
if (first != null)
doSignal(first); // 将节点转移到同步队列
}
}
五、AQS性能优化秘籍
5.1 自旋优化策略
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
// 在第一次失败后立即park会降低吞吐量
// 适当自旋可以提高性能
if (自旋次数 < MAX_SPIN_COUNT) {
if (tryAcquire(arg)) {
// ...
}
自旋次数++;
} else {
// 进入park
}
}
} finally {
// ...
}
}
5.2 队列跳跃(Barging)优化
非公平锁设计允许新到达线程与队列头节点竞争资源
优势:减少线程切换开销
代价:可能造成队列线程饥饿
5.3 状态更新原子性保障
// 使用Unsafe类实现CAS操作
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
// 偏移量初始化
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long stateOffset;
static {
try {
stateOffset = unsafe.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("state"));
} catch (Exception ex) { throw new Error(ex); }
}
总结与进阶指南
知识图谱:
生产环境建议:
- 优先使用JUC包现有同步器(如ReentrantLock)
- 自定义同步器时做好性能压测
- 监控CLH队列长度(反映系统竞争程度)
- 合理设置超时时间(避免线程无限阻塞)
推荐学习路径:
- Doug Lea《The java.util.concurrent Synchronizer Framework》
- OpenJDK AQS源码(jdk/src/share/classes/java/util/concurrent/locks)
- 使用JITWatch观察AQS的JIT编译过程
- 通过JMH进行并发性能基准测试
理解AQS的底层原理后,您将能够:
- 诊断复杂死锁问题
- 定制高性能分布式锁
- 优化高并发场景下的线程调度
- 深入理解JUC包所有同步器的实现机制
建议结合Netty的EventLoop、Tomcat的Connector线程池等真实案例,观察AQS在工业级系统中的应用场景,完成从理论到实践的闭环学习。