|
|
|
@ -30,32 +30,52 @@ import java.util.TimerTask;
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
public final class EventDispatchThreadHangMonitor extends EventQueue { |
|
|
|
|
//一个标识位用于区分耗时任务时长检测(简单检测)和timer检测
|
|
|
|
|
/** |
|
|
|
|
* 一个标识位用于区分耗时任务时长检测(简单检测)和timer检测 |
|
|
|
|
*/ |
|
|
|
|
private static final int TIMER_CHECK_FLAG = 0; |
|
|
|
|
private static final int EASY_CHECK_FLAG = 1; |
|
|
|
|
//日期事件格式
|
|
|
|
|
/** |
|
|
|
|
* 日期事件格式 |
|
|
|
|
*/ |
|
|
|
|
private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
|
|
|
|
public static final EventDispatchThreadHangMonitor INSTANCE = new EventDispatchThreadHangMonitor(); |
|
|
|
|
//一个timer
|
|
|
|
|
/** |
|
|
|
|
* 一个timer |
|
|
|
|
*/ |
|
|
|
|
private Timer timer; |
|
|
|
|
// 开启间隔检测后两次检测的相隔时间ms
|
|
|
|
|
/** |
|
|
|
|
* 开启间隔检测后两次检测的相隔时间ms |
|
|
|
|
*/ |
|
|
|
|
private static final long CHECK_INTERVAL_MS = 100; |
|
|
|
|
|
|
|
|
|
// 最大的事件允许执行时间,超过该时间则打印堆栈等相关信息
|
|
|
|
|
/** |
|
|
|
|
* 最大的事件允许执行时间,超过该时间则打印堆栈等相关信息 |
|
|
|
|
*/ |
|
|
|
|
private static final long UNREASONABLE_DISPATCH_DURATION_MS = 2000; |
|
|
|
|
|
|
|
|
|
//事件唯一编码,用于方便日志的查看
|
|
|
|
|
/** |
|
|
|
|
* /事件唯一编码,用于方便日志的查看 |
|
|
|
|
*/ |
|
|
|
|
private static long hangCount = 0; |
|
|
|
|
//输出日志所在地址
|
|
|
|
|
/** |
|
|
|
|
* /输出日志所在地址 |
|
|
|
|
*/ |
|
|
|
|
private static final String JOURNAL_FILE_PATH = StableUtils.pathJoin(ProductConstantsBase.getEnvHome(), "journal_log"); |
|
|
|
|
|
|
|
|
|
//类似于一个开关,当该值为默认的false启动时,定时任务在窗口开启前都不会对执行的事件进行检查
|
|
|
|
|
/** |
|
|
|
|
* /类似于一个开关,当该值为默认的false启动时,定时任务在窗口开启前都不会对执行的事件进行检查 |
|
|
|
|
*/ |
|
|
|
|
private boolean haveShownSomeComponent = false; |
|
|
|
|
|
|
|
|
|
//该链表为主要的实现定时任务的容器,在重写的dispatchEvent中由pre方法将DispatchInfo加入到链表,由post方法remove
|
|
|
|
|
/** |
|
|
|
|
* /该链表为主要的实现定时任务的容器,在重写的dispatchEvent中由pre方法将DispatchInfo加入到链表,由post方法remove |
|
|
|
|
*/ |
|
|
|
|
private final LinkedList<DispatchInfo> dispatches = new LinkedList<DispatchInfo>(); |
|
|
|
|
|
|
|
|
|
//一个变量,用于控制easy监测模式的开关
|
|
|
|
|
/** |
|
|
|
|
* /一个变量,用于控制easy监测模式的开关 |
|
|
|
|
*/ |
|
|
|
|
private boolean easyWitch = false; |
|
|
|
|
|
|
|
|
|
public boolean isEasyWitch() { |
|
|
|
@ -65,7 +85,11 @@ public final class EventDispatchThreadHangMonitor extends EventQueue {
|
|
|
|
|
public void setEasyWitch(boolean easyWitch) { |
|
|
|
|
this.easyWitch = easyWitch; |
|
|
|
|
} |
|
|
|
|
//一个变量,用于记录Timer的开关。
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* /一个变量,用于记录Timer的开关。 |
|
|
|
|
* |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
public boolean isTimerWitch() { |
|
|
|
|
return timerWitch; |
|
|
|
@ -92,15 +116,24 @@ public final class EventDispatchThreadHangMonitor extends EventQueue {
|
|
|
|
|
} |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
// 用于堆栈的比较
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* / 用于堆栈的比较 |
|
|
|
|
*/ |
|
|
|
|
public static boolean stackTraceElementIs(StackTraceElement e, String className, String methodName, boolean isNative) { |
|
|
|
|
return e.getClassName().equals(className) && e.getMethodName().equals(methodName) && e.isNativeMethod() == isNative; |
|
|
|
|
} |
|
|
|
|
//用于判断某个堆栈是否在等待另一个事件
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* /用于判断某个堆栈是否在等待另一个事件 |
|
|
|
|
*/ |
|
|
|
|
public static boolean isWaitingForNextEvent(StackTraceElement[] currentStack) { |
|
|
|
|
return stackTraceElementIs(currentStack[0], "java.lang.Object", "wait", true) && stackTraceElementIs(currentStack[1], "java.lang.Object", "wait", false) && stackTraceElementIs(currentStack[2], "java.awt.EventQueue", "getNextEvent", false); |
|
|
|
|
} |
|
|
|
|
//event事件的包装类
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* /event事件的包装类 |
|
|
|
|
*/ |
|
|
|
|
public static class DispatchInfo { |
|
|
|
|
// 上一次被打印的堆栈
|
|
|
|
|
private StackTraceElement[] lastReportedStack; |
|
|
|
@ -202,14 +235,19 @@ public final class EventDispatchThreadHangMonitor extends EventQueue {
|
|
|
|
|
timer = new Timer("EventDispatchThreadHangMonitor", daemon); |
|
|
|
|
timer.schedule(new HangChecker(), initialDelayMs, CHECK_INTERVAL_MS); |
|
|
|
|
} |
|
|
|
|
//消除Timer
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* /消除Timer |
|
|
|
|
*/ |
|
|
|
|
public void stopTimer() { |
|
|
|
|
if (timer != null) { |
|
|
|
|
timer.cancel(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//定时执行的任务
|
|
|
|
|
/** |
|
|
|
|
* /定时执行的任务 |
|
|
|
|
*/ |
|
|
|
|
public class HangChecker extends TimerTask { |
|
|
|
|
@Override |
|
|
|
|
public void run() { |
|
|
|
@ -282,7 +320,9 @@ public final class EventDispatchThreadHangMonitor extends EventQueue {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//检查死锁
|
|
|
|
|
/** |
|
|
|
|
* 检查死锁 |
|
|
|
|
*/ |
|
|
|
|
public static void checkForDeadlock() { |
|
|
|
|
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); |
|
|
|
|
long[] threadIds = threadBean.findDeadlockedThreads(); |
|
|
|
|