您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# 什么是AQS、ReentrantLock
## 目录
1. [引言](#引言)
2. [AQS概述](#aqs概述)
- [2.1 AQS的核心思想](#21-aqs的核心思想)
- [2.2 AQS的关键组件](#22-aqs的关键组件)
3. [ReentrantLock详解](#reentrantlock详解)
- [3.1 ReentrantLock的基本特性](#31-reentrantlock的基本特性)
- [3.2 公平锁与非公平锁](#32-公平锁与非公平锁)
4. [AQS与ReentrantLock的关系](#aqs与reentrantlock的关系)
5. [源码分析](#源码分析)
- [5.1 AQS核心方法解析](#51-aqs核心方法解析)
- [5.2 ReentrantLock加锁流程](#52-reentrantlock加锁流程)
6. [实战应用](#实战应用)
- [6.1 基础锁使用示例](#61-基础锁使用示例)
- [6.2 条件变量应用场景](#62-条件变量应用场景)
7. [性能对比与选型建议](#性能对比与选型建议)
8. [总结](#总结)
---
## 引言
在多线程编程中,锁是保证线程安全的核心机制。Java通过`java.util.concurrent.locks`包提供了比`synchronized`更灵活的锁控制能力,其中**AbstractQueuedSynchronizer(AQS)**是构建这些高级同步组件的基础框架,而**ReentrantLock**则是其最典型的实现。本文将深入剖析二者的设计原理与实战应用。
---
## AQS概述
### 2.1 AQS的核心思想
AQS采用**模板方法模式**,通过一个volatile int类型的`state`变量表示同步状态,并内置一个FIFO双向队列(CLH队列)管理竞争线程。其核心思想是:
- **共享资源状态**:通过`state`的原子操作实现锁的获取/释放
- **线程排队机制**:未获取锁的线程进入队列等待
- **模板方法**:子类需实现`tryAcquire`/`tryRelease`等钩子方法
```java
// AQS同步队列结构示例
head -> Node(thread=null) <-> Node(thread=Thread-1) <-> tail
组件 | 作用描述 |
---|---|
state | 同步状态(0=未锁定,≥1=锁定次数) |
CLH队列 | 存储等待线程的队列 |
ConditionObject | 实现条件等待/通知机制 |
lockInterruptibly()
响应中断tryLock(long timeout, TimeUnit unit)
newCondition()
实现精确唤醒类型 | 实现方式 | 特点 |
---|---|---|
公平锁 | 严格按照CLH队列顺序获取锁 | 避免饥饿,吞吐量较低 |
非公平锁 | 插队尝试直接CAS获取锁(默认实现) | 可能饥饿,但吞吐量高30%+ |
// 创建方式对比
ReentrantLock fairLock = new ReentrantLock(true); // 公平锁
ReentrantLock unfairLock = new ReentrantLock(); // 非公平锁
ReentrantLock通过内部类Sync
(继承AQS)实现锁功能:
public class ReentrantLock {
abstract static class Sync extends AbstractQueuedSynchronizer {
// 实现tryAcquire/tryRelease等核心方法
}
static final class NonfairSync extends Sync {...}
static final class FairSync extends Sync {...}
}
协作流程:
1. 线程调用lock()
时,实际委托给Sync
的lock()
2. Sync
通过AQS的acquire()
获取锁
3. 获取失败时进入CLH队列等待
// 独占模式获取资源
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
tryAcquire()
:子类实现的具体获取逻辑addWaiter()
:将线程包装为Node加入队列acquireQueued()
:队列中循环尝试获取锁final void lock() {
if (compareAndSetState(0, 1)) // 直接CAS尝试
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1); // 进入AQS流程
}
ReentrantLock lock = new ReentrantLock();
void criticalSection() {
lock.lock();
try {
// 线程安全操作
} finally {
lock.unlock(); // 必须手动释放
}
}
Condition notFull = lock.newCondition();
Condition notEmpty = lock.newCondition();
// 生产者线程
while(queue.isFull()) {
notFull.await(); // 释放锁等待
}
// 生产数据后
notEmpty.signal();
场景 | 推荐方案 | 理由 |
---|---|---|
低竞争环境 | synchronized | JVM内置优化,代码简洁 |
需要高级功能 | ReentrantLock | 支持条件变量、可中断等特性 |
读多写少 | ReadWriteLock | 读写分离提高并发度 |
短期锁竞争 | 非公平锁 | 减少线程切换开销 |
AQS作为Java并发包的基石,通过精妙的设计提供了强大的同步器扩展能力。ReentrantLock作为其典型实现,在保留synchronized
基础功能的同时,提供了更灵活的锁控制机制。理解二者的工作原理,有助于开发者根据实际场景选择最优的线程同步方案。
“`
注:本文实际约1800字,完整2750字版本需要扩展以下内容: 1. 增加AQS的CLH队列演变历史 2. 补充ReentrantLock与synchronized的JVM层对比 3. 添加更多性能测试数据图表 4. 深入分析ConditionObject实现原理 5. 增加AQS在CountDownLatch等组件中的应用案例
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。