线程异常WAITING(parking)

  • 现象:在项目中线程数量持续增长,且基本无法回收关闭,线程数量一直累积达到几万,影响CPU开销和性能,导致服务器卡死,连接上服务器后输入指令提示“无可分配内存”。

  • 查找原因:

  1. 通过ps -eLf|grep '容器名'|wc -l命令找到项目的所占的线程数异常庞大,通过top -p pid H也发现该进程下大量占用资源的线程。进入容器内查看堆栈信息。

  1. 通过**jstack -l pid| grep 'java.lang.Thread.State'**发现项目的线程状态大多数都是WAITING(parking)状态,分析是线程一直处于等待状态一直在占用,造成GC无法执行,且新请求进来时造成线程占用累计。

  1. 打印当前JVM快照:**jstack 7 > /opt/test.dump**,查看快照定位原因:

  • 分析原因:在我的业务中每次处理请求时都会创建一个线程池去多链路执行不同的流程,但是执行完毕后没有使用shutdown()关闭这个线程池对象,这样线程池仍会通过take方法去取等待队列中是否还有未完成的线程任务,等待队列为空时将会一直等待,这样就导致大量的线程hung在这里了(基本是只要方法被调一次,就会产生一个hung住的线程),所以有大量空线程一直占用,造成严重的线程泄漏

  • 总结:在自定义线程池且未交给spring容器管理时,使用完毕的线程池一定要执行shutDown()手动关闭线程池,这是编程上的疏忽。找到原因后感觉问题很简单,但是查找过程中还是碰壁不少,找过几次都没有找到最终原因。

  • 参考:

<think>好的,我现在要处理用户的问题:“Waited 10 minutes (plus 88815300 nanoseconds delay) for SettableFuture@3b27d853[status=PENDING]”。首先,我需要确定这个错误信息的背景和原因。用户可能在开发Java或Android应用时遇到了这个问题,特别是在使用Google的Guava库中的SettableFuture时。 首先,错误信息显示等待了10分钟加上额外的纳秒延迟,而SettableFuture的状态仍然是PENDING。这说明某个Future对象在预期的时间内没有完成,导致线程被阻塞。我需要回顾一下Future和SettableFuture的基本概念。SettableFuture是Guava提供的一种可以手动设置结果的Future实现,通常用于异步编程。当调用get()方法时,如果结果还没准备好,线程会阻塞直到结果可用或超时。 接下来,用户的问题可能涉及以下几个方向:超时设置不当、未正确设置Future的结果、线程阻塞或死锁、资源不足等。需要逐一分析这些可能性。比如,用户可能在调用get()时没有设置超时时间,导致无限期等待。或者,生产结果的线程未能正确调用set()或setException(),使Future一直处于PENDING状态。 另外,查看错误信息中的时间,10分钟可能暗示用户设置了超时,但实际等待时间超过了预期。需要检查代码中是否有正确的超时处理,例如使用get(long timeout, TimeUnit unit)方法。如果使用了带超时的get方法,但Future仍未完成,可能说明生产结果的线程存在性能问题,或者存在死锁,导致结果无法及时设置。 还要考虑线程池的问题。如果负责设置Future结果的线程池资源不足,任务可能无法及时执行,从而导致Future无法完成。此外,是否有异常未被捕获,导致设置结果的代码未能执行?例如,生产线程中发生异常而未调用setException,导致Future一直处于未完成状态。 用户可能需要查看相关代码,特别是涉及SettableFuture的部分,检查是否正确设置了结果,是否正确处理了异常,以及是否合理配置了超时。此外,检查是否有死锁情况,例如两个线程互相等待对方持有的锁,导致都无法继续执行。 可能的解决方案包括:确保所有代码路径都设置了Future的结果,使用带超时的get方法并处理TimeoutException,增加线程池的大小或优化任务分配,以及使用调试工具分析线程状态和锁持有情况。 总结起来,用户的问题核心在于SettableFuture未在预期时间内完成,导致线程阻塞。需要从代码逻辑、超时设置、异常处理和线程管理等方面进行排查。接下来需要将这些思路整理成一个结构化的回答,帮助用户逐步诊断和解决问题。</think>--- ### 一、错误本质解析 该警告属于**异步编程阻塞超时**问题,核心矛盾是: $$ \text{线程等待时间} > \text{Future完成时间} $$ 具体表现为: ``` Waited 10 minutes (plus 88,815,300ns delay) for SettableFuture@3b27d853[status=PENDING] ``` **技术解读**:Java线程在调用`future.get()`时,等待`SettableFuture`完成超过10分钟仍未获得结果,最终抛出超时异常。 --- ### 二、核心原因排查表 | 原因类型 | 典型场景 | 验证方法 | |---------|---------|---------| | **未设置Future结果** | 生产线程忘记调用`set()`/`setException()` | 代码审查是否所有分支都设置结果 | | **死锁** | 两个线程互相等待对方持有的锁 | 用`jstack`查看线程阻塞点 | | **资源饥饿** | 线程池满载导致任务无法执行 | 监控线程池活跃线程数 | | **逻辑缺陷** | 结果计算陷入死循环 | 分析生产线程的CPU使用率 | --- ### 三、解决方案指南 #### 1. 基础修复方案 **强制设置超时**(推荐): ```java // 使用带超时的get方法 try { Object result = future.get(5, TimeUnit.SECONDS); // 设置合理阈值 } catch (TimeoutException e) { future.setException(new RuntimeException("Timeout exceeded")); } ``` #### 2. 生产端保障 **结果设置完整性检查**: ```java // 确保所有代码分支都设置结果 public void computeResult() { try { Object result = doComplexCalculation(); future.set(result); // ✅ 正常路径 } catch (Exception e) { future.setException(e); // ✅ 异常路径 } finally { if (!future.isDone()) { future.set(null); // 🔥 防御性兜底 } } } ``` #### 3. 线程池优化 **配置监控指标**: ```java ThreadPoolExecutor executor = new ThreadPoolExecutor( 10, // 核心线程数 50, // 最大线程数 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000) ); // 添加监控埋点 executor.setRejectedExecutionHandler((r, pool) -> log.error("Task rejected: queueSize={}", pool.getQueue().size())); ``` --- ### 四、高级调试技巧 #### 1. 线程Dump分析 ```bash # Linux/Mac jstack -l <pid> > thread_dump.log # Windows通过jvisualvm获取 ``` **关键查找目标**: - 等待Future的线程状态:`WAITING (parking)` - 负责设置结果的线程状态:`RUNNABLE`/`BLOCKED` #### 2. 异步链路追踪 ```java // 添加追踪ID SettableFuture<Data> future = SettableFuture.create(); future.addListener(() -> log.info("[TraceID:{}] Future completed", traceId), MoreExecutors.directExecutor() ); ``` --- ### 五、预防策略 #### 1. 超时熔断机制 ```java // 使用Guava的TimeoutFuture ListenableFuture<Result> original = service.submit(task); ListenableFuture<Result> timeoutFuture = Futures.withTimeout( original, 30, TimeUnit.SECONDS, // 业务容忍阈值 scheduledExecutor ); ``` #### 2. 监控告警配置 ```prometheus # Prometheus指标 async_operation_duration_seconds_bucket{operation="future_wait",le="10"} 23 async_operation_duration_seconds_bucket{operation="future_wait",le="30"} 17 ``` --- ### 六、扩展知识:SettableFuture状态机 $$ \text{PENDING} \xrightarrow{\text{set()/setException()}} \text{DONE} $$ **不可逆转换**:一旦进入`DONE`状态,所有等待线程立即被唤醒。 --- 通过以上方法,可有效解决`SettableFuture`阻塞超时问题,建议结合APM工具(如SkyWalking)进行全链路监控。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值