问题详细

发现Java应用服务器常年cpu占满的状态,执行top命令发现是某个java进程占满cpu资源。如果网络请求并发大的话,可能直接导致宕机

具体原因

通过几行linux命令,定位到看如下代码:
InputStream in = null;
in = socket.getInputStream();
int count = 0;
while (count == 0) {
count = in.available();//死循环代码消耗cpu
}
这段代码是处理请求后的响应,希望读到输入流里面总的字节大小,且有时候因为网络原因无法一次读到结果,所以加上while循环,但如果一直读不到,那就麻烦了,死循环可能一直执行下去,或者会执行到超时时间自己断开。无论哪种情况,只要依然要发送请求,给运维人员的感觉就是cpu一直被占满。
注:如何定位到问题代码见补充

解决办法

为避免死循环,需要在适当的时候,break出循环。请看修改后的代码:

InputStream in = null;
 in = socket.getInputStream();
 int count = 0;
 int trytimes =0;
 while (count == 0) {
 count = in.available();
 trytimes++;
 if(trytimes>maxCustomTimes && count ==0) {
 break;
 }
 }
 log.info("-- trytimes: “+ trytimes+”, – count"+count);
 if(count!=0) {
 byte[] bs = new byte[count];
 … //读取输入流里面的内容
 }


注:maxCustomTimes 写到配置里面,我设置的是2000000次如果还读不到输入流,可能真的
不会有什么返回到客户端了,直接跳出循环,跳出后判断输入流里面是否有内容,有的话就读出
来,没有的话忽略,或者再break之前,写一些公共返回,提示操作人员没有收到服务端响应。

补充

如何从占满cpu的进程中找到耗费cup资源多的线程,继而找到线程详细信息定位到java类及发生死循环的代码行?
[步骤1]确定java进程编号
在linux服务器上执行top
找到占满cpu线程的PID(进程编号)
[步骤2]查看java中进程里面线程的占比
top -p 进程号-H
[步骤3]查看线程信息
jstack 进程号 |grep -A 10 线程号(16进制)
注:步骤2和步骤3中的进程号为步骤1找出的进程号; 16进制的线程号从步骤2查到的线程号(10进制)转换而来。