前言
记一次Jstack寻找线程过多原因,本文不具备权威性,文字都是根据个人理解白话表示
一、Jstack是什么?
JDK自带线程分析工具,可以用来查看java程序内线程的信息,如线程状态或获取锁的状态,使用之前需要配置好java环境。
二、使用步骤
1.实际问题
公司内部项目中某一个项目产生大量线程,工程使用netty客户端接收远端数据发送到netty服务器。
首先登陆linnux系统,查看占用该工程端口号的进程pid。
命令如下:netstat -tunlp | grep 5002,当然相同效果的linnux命令都有很多种,选取其中一种就可以。
发现该项目进程为1751进程。
通过命令top -Hp 1751查案进程下到底有多少线程在运行。
标红位置为该进程下的总线程数量,查看发现有128个线程,由于是改进之后的结果。之前是有1500个线程。
接下来,查看进程详细信息,就该使用到jstack了。我们来看看为什么
会有这么多线程,打印线程详细日志。
jstack -l >> 1.txt 由于在远程服务器,所以输出文件,直接查看文件。
发现有大量nioEventLoopGroup处于运行状态。而且nioEventLoopGroup最大值甚至达到了nioEventLoopGroup-25-64.也就是25线程池的第64个线程
基本可以定位到问题了,因为该线程是netty客户端产生的线程,而正常netty客户端会用一个线程处理数据,虽然有线程池,但是只会取其中一个进行接收。而且大量nioEventLoopGroup的命名是nioEventLoopGroup-线程池标识-线程池内线程是第几个 这种命名的形式,正常讲,不会出现如此多的线程池
查看代码,发现系统重复建了多个netty客户端。
2.坑点
此时会想到如果公用一个netty客户端是不是问题就解决了。
但是netty的客户端虽然使用了线程池,但是接收返回服务端返回数据的时候只有一个线程是有效线程。
所以当初设计为多个客户端是为了能够有效快速的接收服务端返回数据。
而为什么只有一个有效线程的netty客户端会出现nioEventLoopGroup-25-64这个名称呢。是因为客户端与服务端做了重新连接机制,而重新连接会根据之前设置的线程池个数创建线程去增加线程。之前由于没有设置客户端线程数。默认线程数为cpu总核数2,就是32核2,所以最大值达到了64.
故解决方式。只允许客户端线程池只有一个线程进行重连和接收返回数据。
设置
EventLoopGroup workerGroup = new NioEventLoopGroup(1);
总结
这样减少了线程的总数。只是简单的解决方式,暂未看到其他影响,线程稳定不会增加。不会由于重连导致出现新的线程使之前的线程无用。本文章只是用于记录自己工作中遇到解决的问题非指导性文章。