当前位置: 首页 > 科技观察

优化排查线程阻塞:CompletableFuture与DiscardPolicy

时间:2023-03-13 00:22:17 科技观察

本文转载自微信公众号《偷偷前进》,作者cscw。转载本文请联系SneakUp公众号。问题发现1前天老大通过prometheus发现这几天tomcathttpbusy状态的线程一直在线性增长。每天添加3道排查问题1:找到繁忙的线程在哪里。通过jvm自带的jps命令可以找到服务对应的进程ID:66182$>$top-Hp66182$pidstat-u-p6618215大部分线程正常,CPU使用率不高,而且线程ID变化很快,基本排除死循环和CPU空转的问题2:既然不是死循环,CPU空转。那是代码阻塞的问题吗?导出66182进程的stack文件jvmjstack-l66182>block66182.jstack。因为我知道是http线程的问题。http开头一般是http-nio。可以使用grep-A15'http-nio'block66182.jstack输出一些关键信息。找了半天,大部分http都正常。然后还找到了项目代码updateXYDVerifiedCodeByDate之类的。定位到具体后发现是定时任务。3查看xxl-task调度日志。凌晨调度了10次,失败了3次,这与prometheus中发现的繁忙http线程的增加是一致的。后来改为future.get(15,TimeUnit.SECONDS);。然后每15秒会报错一次。但是promethues监控的verifiedCodeQueryExecutor的线程队列是空的。4.1promethues监听的线程队列数为空5无任务CompletableFuture的get方法还在执行,查看verifiedCodeQueryExecutor的定义。发现阻塞队列的拒绝策略是DiscardPolicy。也就是任务被丢弃不执行,封装的CompletableFuture自然不会返回结果,所以会一直阻塞,如果改了代码就会超时返回。真相大白了。....解决问题1:队列是无限的,好像不太好,不接受2:自定义拒绝策略newRejectedExecutionHandler(){@OverridepublicvoidrejectedExecution(Runnabler,ThreadPoolExecutorexecutor){thrownewRuntimeException("oversizeerror");}}3:但是考虑到任务必须被处理掉,任务不能被丢弃。所以暂时使用CallerRunsPolicy策略,executor.setRejectedExecutionHandler(newThreadPoolExecutor.CallerRunsPolicy());4:后期优化