Semaphore 的公平性:分析其内部 AQS 队列对等待时间最长线程的许可证优先分配机制

小涛姑娘_4273

小涛姑娘_4273

2026-05-01

598人浏览

原创

semaphore公平性本质是aqs fifo队列保障“等待最久者优先获许可”,通过hasqueuedpredecessors()判断入队顺序,release时固定唤醒队首节点,解决线程饥饿但不保证响应时间均等,适用高可预测性场景。

semaphore 的公平性:分析其内部 aqs 队列对等待时间最长线程的许可证优先分配机制

Semaphore 的公平性,本质是通过 AQS(AbstractQueuedSynchronizer)的 FIFO 同步队列实现“等待时间最长者优先获得许可”的调度逻辑,而非依赖线程优先级或系统调度器偏好。这种机制不保证执行时间均等,但确保入队顺序即服务顺序。

公平模式如何识别“等待最久的线程”

关键在于 hasQueuedPredecessors() 方法的调用判断:

  • 每次线程调用 acquire() 时,公平模式下的 FairSync.tryAcquire() 会先检查同步队列中是否存在比当前线程更早入队的节点
  • hasQueuedPredecessors() 返回 true,说明队列非空且头结点后有等待者 → 当前线程必须排队,不能抢占
  • 只有当该方法返回 false(即队列为空,或当前线程是队列首节点)时,才尝试用 CAS 更新许可计数器

许可证分配严格遵循队列头部唤醒

释放许可时(release()),AQS 不随机唤醒,而是固定唤醒同步队列中第一个有效等待节点:

  • 每个等待线程被封装为 Node,包含前驱/后继指针和 waitStatus
  • release() 触发 unparkSuccessor(head),仅唤醒 head.next 所指节点
  • 被唤醒线程重新竞争许可,若成功则成为新 head;失败则继续等待——整个过程天然形成 FIFO 链式传递

为什么“等待时间最长”不等于“响应时间最短”

公平性只约束排队与唤醒顺序,不控制线程实际运行时机:

  • 即使线程排在队首,仍需经历上下文切换、CPU 调度、JVM 线程状态转换等开销
  • 若临界区操作耗时差异大(如有的线程 sleep(100),有的 sleep(10)),队列顺序无法抵消执行时间偏差
  • AQS 唤醒与操作系统线程调度之间存在非精确对齐,可能造成微小错位,但不破坏整体 FIFO 语义

公平模式的实际适用边界

它真正解决的是资源长期紧张下的线程饥饿问题,而非提升实时性:

  • 当许可数远小于并发线程数(例如 2 个许可、50 个线程持续争抢),非公平模式下新线程反复插队,旧线程可能永远等不到许可;公平模式则保障每个线程最多等待 N 轮即可轮到
  • 适合对服务可预测性要求高、且能接受吞吐量下降约 20–30% 的场景,如金融交易网关的请求限流、审计日志写入门控
  • 若临界区极短(
PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

2023.08.10

3698

6

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

2025.09.05

470

5

golang map相关教程
golang map相关教程

本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

2025.11.16

323

7

golang map原理
golang map原理

本专题整合了golang map相关内容,阅读专题下面的文章了解更多详细内容。

2025.11.17

493

20

java判断map相关教程
java判断map相关教程

本专题整合了java判断map相关教程,阅读专题下面的文章了解更多详细内容。

2025.11.27

263

6

LLVM自定义Pass怎么写
LLVM自定义Pass怎么写

本专题聚焦LLVM自定义Pass开发,整理Pass类结构、run()方法、PreservedAnalyses、CMake构建、插件注册、-load-pass-plugin加载和测试用例编写流程。

2026.09.30

20

10

LLVM RISC-V参数配置教程
LLVM RISC-V参数配置教程

本专题介绍LLVM对RISC-V基础ISA和扩展的支持方式,涵盖RV32、RV64、标准扩展、实验性扩展、厂商扩展、-menable-experimental-extensions和版本差异。

2026.09.30

0

14

LLVM IR中间表示入门指南
LLVM IR中间表示入门指南

本专题整理LLVM IR的核心概念,包括中间表示作用、模块结构、函数、基本块、SSA形式、类型系统和常见语法,帮助新手理解LLVM编译流程中的关键层。

2026.09.30

0

12

PDF转图片方法
PDF转图片方法

需要把 PDF 页面用于上传、预览、分享或图片归档时,PDF 转图片方法专题整理 JPG/PNG 格式选择、逐页导出、清晰度设置、批量下载和结果检查等流程,帮助用户稳定完成 PDF 图片化处理。

2026.09.30

20

26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.4万人学习