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的设计智慧。如果觉得有收获,别忘了点赞收藏哦

相关推荐
yuuki23323316 分钟前
【C语言】文件操作(附源码与图片)
c语言·后端
IT_陈寒20 分钟前
Python+AI实战:用LangChain构建智能问答系统的5个核心技巧
前端·人工智能·后端
无名之辈J43 分钟前
系统崩溃(OOM)
后端
码农刚子1 小时前
ASP.NET Core Blazor简介和快速入门 二(组件基础)
javascript·后端
间彧1 小时前
Java ConcurrentHashMap如何合理指定初始容量
后端
catchadmin1 小时前
PHP8.5 的新 URI 扩展
开发语言·后端·php
少妇的美梦1 小时前
Maven Profile 教程
后端·maven
白衣鸽子1 小时前
RPO 与 RTO:分布式系统容灾的双子星
后端·架构
Jagger_1 小时前
SOLID原则与设计模式关系详解
后端
间彧1 小时前
Java: HashMap底层源码实现详解
后端