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

Java线程卡死问题定位

最近在做ftp下载的时候遇到一个诡异的问题,一个方法调了几次后一点反应也没有,连日志都不打,代码如下,可以思考下为啥方法调用后日志都不打

 其实答案很简单,这个方法加了锁,肯定是有其他线程占用了这个锁,导致后续的方法无法执行,但是最诡异的不是这个,而是等了一个晚上这个锁都没被释放,到底是什么地方导致了这个线程的卡死呢?

这时我们就要通过查看线程堆栈信息来看下线程运行情况:

1. 确定卡死线程的 PID

首先需要获取 Java 进程的 ID(PID):

# 查找Java进程(包含main类或关键词)
ps aux | grep java
# 或使用jps(JDK自带工具)
jps -l

2. 生成线程 dump 文件

使用 jstack 命令生成线程堆栈信息,下面的12345就是pid:

jstack -l 12345 > thread_dump.txt
  • -l 参数:显示锁的详细信息(如等待的锁、持有锁的线程)。
  • 输出保存到 thread_dump.txt 文件以便分析。

3. 分析线程状态

在线程 dump 文件中,查找以下关键信息:

3.1 寻找卡死线程的状态

常见的卡死状态包括:

  • BLOCKED:线程正在等待获取锁。
  • WAITING 或 TIMED_WAITING:线程在等待某个条件(如 Object.wait()Thread.sleep())。
  • RUNNABLE:线程看似在运行,但可能在执行死循环或 IO 阻塞。
3.2 查找锁争用信息

重点关注以下内容:

  • 锁的持有者:找到持有锁的线程(通常显示为 locked <0x00000000>)。
  • 等待锁的线程:显示为 waiting to lock <0x00000000>

具体分析 

我们先查找lock的线程,发现好几个线程是blocked状态,上面还有线程名称,所以以后遇到一个线程比较耗时的情况,建议使用乐观锁,遇到失败快速返回,不然大量线程处于等待中容易耗光线程。

在这个信息里面我们还能看到代码执行到哪个类的第几行遇到了锁,并且指明了等待哪个锁,waiting to lock xxxx,我们只要根据这个锁的编号就能找到卡死的线程了

接下去我们找到一个运行中的线程,通过locked xxxx我们确认了这个线程持有锁 ,上面的FilePartServiceImpl.java:986表示这个线程当前运行的位置

我们通过这些信息找到堵塞的代码

原来线程是卡在ftp下载这一步了

优化建议 

1.使用分布式锁的乐观锁模式代替synchronized

RLock lock = redissonClient.getLock(ValueConstant.REDIS_SYNC_FTP_FILEPART);
if (!lock.tryLock()) {// 没有拿到锁直接返回throw new ServiceFailException("同步线程运行中,请稍后再试");
}
try {//业务处理
} finally{//释放锁if (lock.isLocked() && lock.isHeldByCurrentThread()) {lock.unlock();}
}

2.使用ftp保活机制

setControlKeepAliveTimeout(long controlIdleSeconds) 用于设置控制连接保活消息的发送间隔时间,防止在长时间文件传输(上传 / 下载)期间连接因空闲被服务器关闭。

//设置保活时间,保持连接
ftp.getClient().setControlKeepAliveTimeout(30);

3.关于涉及网络操作的建议

凡是涉及到网络方面的操作,像ftp,http等的调用,一定要考虑保活或者设置超时时间,否则很容易造成线程卡死

http://www.xdnf.cn/news/12501.html

相关文章:

  • 商业卫星推进与控制系统电源芯片的国产替代研究
  • 智谱清言沉思智能体,天工智能体,agenticSeek等AI Agent测试记录
  • 黄晓明新剧《潜渊》定档 失忆三面间谍开启谍战新维度
  • 一些免费的大A数据接口库
  • LLaMA-Factory的5种推理方式总结
  • 使用vtk8.2.0加载dicom图像
  • 界面开发框架DevExpress XAF实践:集成.NET Aspire后如何实现数据库依赖?
  • 【AUTOSAR COM】E2E的不同profiles的含义以及应用
  • 批量文件改名具体操作方案
  • USB扩展器与USB服务器的2个主要区别
  • 机器人编程界面
  • CMake 为 Debug 版本的库或可执行文件添加 d 后缀
  • 第五讲——一元函数微分学的几何应用
  • 飞马LiDAR500雷达数据预处理
  • LLMControlsArm开源程序是DeepSeek 控制熊猫机械臂
  • Python基础语法全解:从入门到精通的简明指南
  • 初始结构体,整型提升及操作符的属性
  • RockyLinux9.6搭建k8s集群
  • 一键编译包含多个独立模块和应用的工程(linux cmake)
  • 单片机0-10V电压输出电路分享
  • 微信小程序动态效果实战指南:从悬浮云朵到丝滑列表加载
  • JVM——打开JVM后门的钥匙:反射机制
  • 408第一季 - 数据结构 - 数组和特殊矩阵
  • 代码安全规范1.1
  • STM32标准库-TIM输出比较
  • table表格合并,循环渲染样式
  • git commit 执行报错 sh: -/: invalid option
  • SpringBoot+MySQL家政服务平台 设计开发
  • OpenAI对抗法庭命令:捍卫ChatGPT用户隐私之战
  • mybatis的if判断==‘1‘不生效,改成‘1‘.toString()才生效的原因