什么是AQS、ReentrantLock

发布时间:2021-10-21 10:48:52 作者:iii
来源:亿速云 阅读:181
# 什么是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

2.2 AQS的关键组件

组件 作用描述
state 同步状态(0=未锁定,≥1=锁定次数)
CLH队列 存储等待线程的队列
ConditionObject 实现条件等待/通知机制

ReentrantLock详解

3.1 ReentrantLock的基本特性

3.2 公平锁与非公平锁

类型 实现方式 特点
公平锁 严格按照CLH队列顺序获取锁 避免饥饿,吞吐量较低
非公平锁 插队尝试直接CAS获取锁(默认实现) 可能饥饿,但吞吐量高30%+
// 创建方式对比
ReentrantLock fairLock = new ReentrantLock(true);  // 公平锁
ReentrantLock unfairLock = new ReentrantLock();    // 非公平锁

AQS与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()时,实际委托给Synclock() 2. Sync通过AQS的acquire()获取锁 3. 获取失败时进入CLH队列等待


源码分析

5.1 AQS核心方法解析

// 独占模式获取资源
public final void acquire(int arg) {
    if (!tryAcquire(arg) && 
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}
  1. tryAcquire():子类实现的具体获取逻辑
  2. addWaiter():将线程包装为Node加入队列
  3. acquireQueued():队列中循环尝试获取锁

5.2 ReentrantLock加锁流程(非公平锁)

final void lock() {
    if (compareAndSetState(0, 1))  // 直接CAS尝试
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);  // 进入AQS流程
}

实战应用

6.1 基础锁使用示例

ReentrantLock lock = new ReentrantLock();
void criticalSection() {
    lock.lock();
    try {
        // 线程安全操作
    } finally {
        lock.unlock();  // 必须手动释放
    }
}

6.2 条件变量应用场景

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等组件中的应用案例

推荐阅读:
  1. 多线程(十一、AQS原理-ReentrantLock的条件队列Condition)
  2. 多线程(十、AQS原理-ReentrantLock公平锁)

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java aqs reentrantlock

上一篇:如何使用Java实现JActor 2.2.0 RC3发布Actor模式

下一篇:如何实现反向代理、负载均衡

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》