咱們常常碰到一些定時任務卡死或者執行時間很長,這樣的問題咱們排查手段比較經常使用的是jstack命令html
來查看線程堆棧,而後根據咱們監控中的threadId或者threadName來查找線程詳細堆棧看卡在哪一個方法。java
經常使用命令以下:chrome
jstack pid >jstack.logapp
如今咱們能夠提供界面查看卡死線程堆棧ui
controller代碼線程
@RequestMapping("/getStackTrace") @ResponseBody public String getStackStace(HttpServletRequest request, HttpServletResponse response) { logger.debug("執行選擇的Job對象 queryQuartzLog quartzLog:"); try { String threadId=request.getParameter("threadId"); if(StringUtils.isBlank(threadId)){ return ""; } ThreadInfo info = ThreadUtilities.getExtendThreadInfo(Long.valueOf(threadId)); List<String> list=new ArrayList<String>(); StackTraceElement[] st=info.getStackTrace(); int index=0; MonitorInfo[] monitors=info.getLockedMonitors(); for(StackTraceElement e:st){ StringBuffer sb=new StringBuffer(); if(index>0){ sb.append(" <- "); sb.append(System.getProperty("line.separator")); } sb.append(e.toString()+ "\n"); list.add(sb.toString()); if (monitors != null) { for (MonitorInfo mi : monitors) { if (mi.getLockedStackDepth() == index) { list.add(" <- - locked "+mi.toString()); } } } index++; } return generateHtml("vm/getStackTrace.vm", list); } catch (Exception e) { logger.error("doRunQuartzJob 執行選擇的Job對象出錯", e); return "fail"; } }
ThreadUtilities.getExtendThreadInfodebug
public static ThreadInfo getExtendThreadInfo(final long threadID) { ThreadInfo ti = null; final ThreadMXBean threadMBean = ManagementFactory.getThreadMXBean(); if (threadMBean.isObjectMonitorUsageSupported()) { // VMs that support the monitor usage monitoring ThreadInfo[] infos = threadMBean.dumpAllThreads(true, false); for (ThreadInfo info : infos) { if (info.getThreadId() == threadID) { ti = info; break; } } } else { // VM doesn't support monitor usage monitoring ti = threadMBean.getThreadInfo(threadID, Integer.MAX_VALUE); } return ti; }
而後經過vm代碼將堆棧展現在頁面上code
getStackTrace.vmhtm
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> <meta name="description" content="" /> <meta name="Keywords" content="" /> <title>job logs</title> </head> <body> <div> #foreach($element in $data) $element<br/> #end </div> </body> </html>
public class BaseController { private static final VelocityEngine ve = new VelocityEngine(); private static final Logger logger = LoggerFactory.getLogger(QuartzController.class); static{ // 初始化Velocity引擎 InputStream is = BaseController.class.getResourceAsStream("/velocity.properties"); Properties properties = new Properties(); try { properties.load(is); } catch (IOException e) { e.printStackTrace(); } ve.init(properties); } public String generateHtml(String vmTemplate,Object obj){ StringWriter sw = new StringWriter(); try { VelocityContext ctx = new VelocityContext(); ctx.put("data", obj); ve.getTemplate(vmTemplate,"UTF-8").merge(ctx, sw); } catch (Exception e) { logger.error("轉化vm模板出錯",e); }finally{ if(sw!=null){ try { sw.close(); } catch (IOException e) { e.printStackTrace(); } } } return sw.toString(); } }