当前位置: 首页 > news >正文

服务RejectedExecutionException问题对Semaphore的思考

目录

1. 问题背景

2. Java并发控制方式

3. Java限流控制方式


1. 问题背景

回放引擎服务隔一段时间就会发生一次服务拒绝,报错:Exception:RejectedExecutionException

通过服务监控平台查看stack信息,发现有很多线程waiting,点开waiting线程,可以看到具体是哪个类的哪一行出现了锁

阻塞信息解读:java.util.concurrent.Semaphore$NonfairSync@406f5dbf

分析:基本含义

  • java.util.concurrent.Semaphore 是 Java 并发包中的一个信号量实现,用于控制同时访问某个资源的线程数量。
  • NonfairSync 表示该信号量采用非公平模式(即新来的线程可能优先于等待队列中的线程获得许可)。

阻塞场景分析
阻塞信息:java.util.concurrent.Semaphore$NonfairSync@406f5dbf
通常说明:

  1. 有线程在尝试获取 Semaphore 的许可时被阻塞,因为当前可用许可数量为 0。
  2. 非公平模式下,等待的线程不会严格按照先后顺序获得许可,可能出现“插队”现象。
  3. 堆栈或日志信息中出现该对象,通常是在分析线程阻塞或死锁时,定位到具体的同步资源。

典型应用场景

  • 限流:限制同时执行的任务数(如连接池、批量任务处理)。
  • 资源保护:如只允许 N 个线程同时访问某个临界区。

常见问题及排查建议

  1. 许可数设置过小
    • 如果初始许可数太低,容易导致大量线程阻塞,影响系统吞吐。
  2. 未及时释放许可
    • 某些线程获得许可后异常退出或忘记release(),导致许可“泄漏”。
  3. 非公平模式下线程饥饿
    • 长时间等待的线程可能一直得不到执行机会。

排查建议:

  • 检查所有acquire()后是否有对应的release()
  • 监控当前信号量的可用许可数(semaphore.availablePermits())。
  • 如需严格控制顺序,可考虑使用公平模式(new Semaphore(permits, true))。

原因分析:

流量回放为了限制对回放服务的最大并发量,采用Semaphore方式控制API调用并发数,具体代码如下:可以看出第二个try 如果异常后,没有释放已获取的信号量,最终导致新的线程无法获取新的许可,系统阻塞。

public class ReplayService{private static final Semaphore semaphore = new Semaphore(32);public void replay(ReplayRequest request){try{semaphore.acquire();}catch(Exception e){return ResultUtil.error(-1,"获取许可失败")}try{//开始调用服务;}catch(Exception e){return ResultUtil.error(-1,"服务返回异常")}try{//回放结果处理;}catch(Exception e){return ResultUtil.error(-1,"结果处理失败")}finally{semaphore.release();}}
}

2. Java并发控制方式

并发控制主要是为了 协调多个线程安全、高效地访问共享资源,避免冲突、死锁或性能下降。
常见方式如下:

(1) 线程同步机制

  • synchronized
    Java 关键字,保证同一时间只有一个线程执行同步代码块。

  • ReentrantLock
    可重入锁,功能比 synchronized 更丰富(支持公平锁、条件变量等)。

  • ReadWriteLock(ReentrantReadWriteLock)
    读写分离锁,允许多个线程同时读,但写操作互斥。

  • StampedLock
    支持乐观读锁,性能更高,适合读多写少场景。

(2) 信号量(Semaphore)

  • 控制同时访问某个资源的线程数量,适合限制并发连接数45。

(3) 倒计时器(CountDownLatch)

  • 等待多个任务完成后再继续执行,常用于多线程任务的协调。

(4)( 栅栏(CyclicBarrier)

  • 多线程到达屏障点后统一执行下一步,适合分阶段任务。

(5) 原子类(AtomicInteger、AtomicLong等)

  • 基于 CAS 操作的无锁并发控制,适合高性能计数器等。

(6) 并发集合

  • ConcurrentHashMap、CopyOnWriteArrayList 等线程安全集合。

(7)线程池(ExecutorService)

  • 控制任务执行线程数,避免频繁创建/销毁线程。

Semaphore(信号量限流)

  • 本质是并发访问数量控制工具,用一个计数器(许可数)限制同时访问某个资源的线程数。
  • 当许可用完时,其他线程会阻塞等待,直到有线程释放许可。
  • 常用于限制最大并发量,例如数据库连接池、并发下载任务、API调用并发数等。

回放引擎为了控制对回放服务的速度,采用Semaphore方式,限制并发数32个线程同时调用服务

3. Java限流控制方式

限流是为了 控制请求速率或并发量,防止系统过载。

常见方式如下:

(1)基于 RateLimiter 的速率限制

  • Guava 提供的 RateLimiter 类,基于令牌桶算法限制 QPS(每秒请求数)12。

(2)固定窗口计数器

  • 在固定时间窗口内统计请求数,超出限制则拒绝请求。

(3)滑动窗口算法

  • 将时间窗口分成多个小格,平滑统计请求数,避免固定窗口的突发问题2。

(4)漏桶算法(Leaky Bucket)

  • 以固定速率处理请求,平滑流量6。

(5)令牌桶算法(Token Bucket)

  • 按固定速率生成令牌,请求需获取令牌才能执行,允许一定突发流量2。

(6)分布式限流

  • 基于 Redis、ZooKeeper 等实现跨节点限流,适合分布式系统。

事后总结:服务拒绝报错时,以为是服务负载太大导致,查看cpu和gc情况,并没有异常,定位到方法后,让AI分析方法中存在的异常,存在严重的信号量泄漏问题。

http://www.dtcms.com/a/545093.html

相关文章:

  • GitLab 钩子 + Jenkins 自动化构建项目
  • 安装Pytorch GPU+CPU版本【通过本地安装解决无法使用pip指令下载问题】
  • DevExpress WinForms中文教程:Data Grid - 如何自定义汇总函数?
  • 西安建设市场诚信信息平台网站wordpress文章缩略图
  • 解锁未来:云原生如何重塑企业数字竞争力
  • 铜陵市建设工程管理局网站专业的网站开发团队
  • AI赋能座舱产品需求开发
  • SENT协议详解
  • 2026年ESWA SCI1区TOP,基于成本差异的跨境公路物流混合车队构成与调度:一种双层规划方法,深度解析+性能实测
  • 2025广州国际物联网产业生态博览会(物联网展)最新技术与亮点揭秘!
  • 【C++】哈希表实现 - 链地址法/哈希桶
  • 建设一个教程视频网站需要什么资质龙岗网络推广公司
  • 后端日志框架
  • 服务器在企业中的作用与价值
  • 《搭建属于自己的网站之网页前端学习》基础入门
  • 拿网站做商标童装网站建设
  • 金融投资网站毕设做网站是不是太low
  • 【pandas】pandas apply 方法详解
  • 散户如何运用券商手机智能T0算法
  • CRMEB-PHP订单删除机制详解
  • 分数阶微分方程谱方法求解
  • 经典“绿叶”算法——SVM回归预测(SVR)算法及MATLAB实现
  • 南漳网站开发wordpress flash加载插件
  • 过度依赖单一工具会带来哪些风险
  • 132-Spring AI Alibaba Vector Neo4j 示例
  • 杜集网站建设免费做网站公司ydwzjs
  • 中心网站设计建筑工程总承包合同范本
  • AWS ECS 健康检查与部署配置最佳实践指南
  • leetcode 205. 同构字符串 python
  • wordpress 纯静态插件wordpress 文章seo