我的网站运行一段时间,Tomcat的CPU突然变成99%,并且以后一直是高CPU,与宕机几乎无异;我的Tomcat平时CPU是0%,有时会出现20%的CPU,我想知道是哪段代码引起的,要优化;......。问题随机出现,无法复现,查找起来真是花时间、真是令人抓狂!
TomProbe可以很容易地定位引起CPU异常的代码,利用Thread.currentThread().setName()方法巧妙地设置代码标记!直接上例子。BigWork.java:
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class BigWork extends HttpServlet{
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException{
System.out.println("BigWork doGet!");
String oldName=Thread.currentThread().getName();
Throwable ex0=null;
System.out.println("oldName="+oldName);
System.out.println("Thread.currentThread()="+Thread.currentThread());
System.out.println("Long.MAX_VALUE="+Long.MAX_VALUE);
try{
long i=0;
long start=System.currentTimeMillis();
Thread.currentThread().setName("BigWork's doGet, i="+i);
while (i<Long.MAX_VALUE){
i++;
if (i%1000000000==0){
Thread.currentThread().setName("BigWork's doGet, sleep!");
try{
Thread.sleep(1);
}
catch (Throwable ex2){
}
Thread.currentThread().setName("BigWork's doGet, i="+i);
}
}
Thread.currentThread().setName("BigWork's doGet, after while(...)");
long end=System.currentTimeMillis();
long cost=end-start;
System.out.println("cost="+cost);
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
PrintWriter out=response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>BigWork</title>");
out.println("</head>");
out.println("<body bgcolor=\"white\">");
out.println("<h1>cost="+(cost/1000)+"s</h1>");
out.println("</body>");
out.println("</html>");
}
catch (Throwable ex1){
ex0=ex1;
ex1.printStackTrace();
}
Thread.currentThread().setName(oldName);
System.out.println("after setName="+oldName);
System.out.println("Thread.currentThread()="+Thread.currentThread());
if (ex0!=null){
if (ex0 instanceof ServletException){
throw (ServletException)ex0;
}
if (ex0 instanceof IOException){
throw (IOException)ex0;
}
}
}
}
(编译、配置、启动Tomcat等省去)启动Tomcat、在浏览器请求BigWork服务,这时Tomcat的窗口显示BigWork的doGet()运行了。
(下图)启动TomProbe、连接到Tomcat,界面显示CPU占用厉害,异常!
(下图)将光标点在高CPU点上,右击鼠标,弹出菜单。
(下图)点“查看线程信息(最新CPU前1-6)”菜单后,显示了前6名CPU线程信息,正是BigWork的doGet()的while (true)循环消耗了大量CPU!
Q1: 好象很不错,但我有点疑惑:上面BigWork.java里2处Thread.currentThread()是同一个线程吗?若不是,岂不是搞乱了。
答:你做的servlet、jsp等网站开发,其实是在填写代码片段。Tomcat等Web Server是这样运行代码的:当有用户请求时,从线程池取出一个空闲线程,执行run()方法,run()方法是这样的:
public void run(){
objectA.method2();
........
objectX.methodn();
}
你的servlet、jsp的doGet()、doPost()、service()等方法必作为一个整体被同一个线程执行,因此一个方法内的多处Thread.currentThread()都是同一个线程。
Q2:我是项目技术负责人,按您的说法,我让项目组每个程序员在自己的代码里加上类似的代码标记,那我就可以利用TomProbe很轻松地发现哪些代码需要优化、哪些程序员代码质量有问题,那岂不是很省事、岂不是太妙了?
答:你的悟性真高!