AQS揭秘:为什么它既不是公平锁也不是非公平锁?

你真的了解AQS吗?

在Java并发编程的世界里,AQS(AbstractQueuedSynchronizer)就像一位"幕后英雄",默默支撑着ReentrantLock、CountDownLatch等众多并发工具的运作。但你有没有想过:AQS本身到底是公平锁还是非公平锁?

答案可能会让你惊讶------AQS两者都不是!它更像是一个"万能工具箱",提供了构建锁和同步器的基础零件,而具体是组装成公平锁还是非公平锁,则完全取决于使用者(也就是基于AQS的子类)的选择。

AQS的"中立"智慧:把选择权交给你

AQS的设计哲学非常精妙:它只负责最基础的工作(比如维护线程等待队列、管理同步状态),而把关键的决策逻辑(比如谁能获得锁、什么时候获得锁)通过"钩子方法"留给子类来实现。

想象一下,AQS就像一家提供场地和基础设备的咖啡馆,而子类(如ReentrantLock)则是具体的经营者------可以选择做成安静的书店咖啡吧(公平锁),也可以做成热闹的快节奏咖啡店(非公平锁),AQS并不干涉具体的经营策略。

关键的"钩子"在哪里?

AQS通过以下几个核心方法将公平性的决定权交给子类:

  • tryAcquire:尝试获取锁的逻辑
  • tryRelease:尝试释放锁的逻辑 正是这些方法的实现,决定了最终是公平还是非公平的行为。

实例:ReentrantLock如何选择公平性

ReentrantLock是AQS最典型的应用,它通过构造函数的fair参数,轻松实现了两种锁模式。

非公平锁:"先到先得?我先试试插队!"

ReentrantLock默认是非公平锁,就像排队买奶茶时总有人想先问问"还需要等多久"------新线程会先"插队"尝试获取锁,成功了就直接拿走,失败了才乖乖去排队。

java 复制代码
// 非公平锁的获取逻辑
protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        // 不管队列有没有人,先CAS抢一波再说
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    // ...
    return false;
}

公平锁:"排队是基本礼仪"

当fair参数为true时,ReentrantLock就变成了公平锁------新线程会先看看队伍里有没有人,有人就自觉排队,没人再尝试获取锁。

java 复制代码
// 公平锁的获取逻辑
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;
        }
    }
    // ...
    return false;
}

关键区别就在于hasQueuedPredecessors()方法------它会检查是否有线程在排队,就像在问"我前面还有人吗?"

为什么AQS要这样设计?

AQS的这种"中立"设计,体现了Java并发框架的高明之处:

  • 不做一刀切:不同场景对公平性的需求不同,AQS不强制选择
  • 性能与公平的平衡:非公平锁吞吐量更高,公平锁保证顺序,用户可以按需选择
  • 灵活性至上:同一个AQS框架,既能实现ReentrantLock,也能实现CountDownLatch等完全不同的同步器

一句话总结

AQS就像一张白纸,本身没有公平或非公平的属性,而是由使用者(子类)通过实现特定方法来描绘出不同的"公平性图景"。理解了这一点,你就真正抓住了Java并发编程的精髓!

希望这篇文章能帮你更轻松地理解AQS的设计智慧。如果觉得有收获,别忘了点赞收藏哦

相关推荐
金銀銅鐵1 小时前
[Java] 用 GUI 展示 EnumSet 增减元素时的内部变化(上)
java·后端·ai编程
念何架构之路2 小时前
go-grpc设计思想
开发语言·后端·golang
system_error_x2 小时前
SpringBoot 集成 Thymeleaf 简洁入门
java·spring boot·后端
步行cgn4 小时前
Spring MVC 视图机制的核心接口与类
java·开发语言·后端·spring·mvc
码事漫谈5 小时前
AI 读你的提示词,其实很没耐心
后端
用户8356290780516 小时前
如何使用 Python 格式化 Excel 单元格中的长文本
后端·python
我命由我123456 小时前
Python 开发 - Python 的 pathlib
java·开发语言·后端·python·学习·java-ee·学习方法
IT_陈寒6 小时前
Java性能优化完全指南
前端·人工智能·后端
电子IT笔记6 小时前
对接群晖NAS,上传和删除踩坑记录
前端·后端
Mk598786 小时前
P4:把 Agent 的记忆搬进 Redis —— AgentScope-Java 工程化实战
后端