John.Ying-应志浩
2 years ago
3 changed files with 288 additions and 5 deletions
@ -0,0 +1,73 @@
|
||||
package com.fr.design.carton.developer; |
||||
|
||||
import java.awt.AWTEvent; |
||||
|
||||
/** |
||||
* EDT事件的包装类,用来额外处理信息 |
||||
* |
||||
* @author John.Ying |
||||
* @since 11.0 |
||||
* Created on 2023/4/14 |
||||
*/ |
||||
public class AwtEventInfo { |
||||
//获取执行该事件的线程
|
||||
private final Thread eventDispatchThread = Thread.currentThread(); |
||||
//在队列中等待执行的事件最后未执行的时间,当有一个事件执行完后就遍历dispatches给该值赋当前时间
|
||||
private long lastDispatchTimeMillis = System.currentTimeMillis(); |
||||
//事件开始的时间
|
||||
private final long startDispatchTimeMillis = System.currentTimeMillis(); |
||||
//awt事件
|
||||
private AWTEvent awtEvent; |
||||
//事件堆栈
|
||||
private StackTraceElement[] stackTrace; |
||||
|
||||
/** |
||||
* 检查是否要给堆栈赋值 |
||||
*/ |
||||
public void checkForHang() { |
||||
if (isNeedToStackTrace()) { |
||||
this.stackTrace = eventDispatchThread.getStackTrace(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 是否需要赋值堆栈满足 |
||||
* 耗时>20ms |
||||
*/ |
||||
private boolean isNeedToStackTrace() { |
||||
return (System.currentTimeMillis() - startDispatchTimeMillis) > EventDispatchDeveloperMode.MAX_TIME |
||||
&& stackTrace == null; |
||||
} |
||||
|
||||
public Thread getEventDispatchThread() { |
||||
return eventDispatchThread; |
||||
} |
||||
|
||||
public long getLastDispatchTimeMillis() { |
||||
return lastDispatchTimeMillis; |
||||
} |
||||
|
||||
public void setLastDispatchTimeMillis(long lastDispatchTimeMillis) { |
||||
this.lastDispatchTimeMillis = lastDispatchTimeMillis; |
||||
} |
||||
|
||||
public long getStartDispatchTimeMillis() { |
||||
return startDispatchTimeMillis; |
||||
} |
||||
|
||||
public AWTEvent getAwtEvent() { |
||||
return awtEvent; |
||||
} |
||||
|
||||
public void setAwtEvent(AWTEvent awtEvent) { |
||||
this.awtEvent = awtEvent; |
||||
} |
||||
|
||||
public StackTraceElement[] getStackTrace() { |
||||
return stackTrace; |
||||
} |
||||
|
||||
public void setStackTrace(StackTraceElement[] stackTrace) { |
||||
this.stackTrace = stackTrace; |
||||
} |
||||
} |
@ -0,0 +1,146 @@
|
||||
package com.fr.design.carton.developer; |
||||
|
||||
|
||||
import com.fr.concurrent.FineExecutors; |
||||
import com.fr.design.carton.EventDispatchThreadHangMonitor; |
||||
import com.fr.design.ui.util.UIUtil; |
||||
import com.fr.log.FineLoggerFactory; |
||||
|
||||
import java.awt.AWTEvent; |
||||
import java.awt.EventQueue; |
||||
import java.awt.Toolkit; |
||||
import java.util.LinkedList; |
||||
import java.util.Timer; |
||||
import java.util.TimerTask; |
||||
import java.util.concurrent.ScheduledExecutorService; |
||||
import java.util.concurrent.TimeUnit; |
||||
|
||||
/** |
||||
* 开发者模式重写的EDT |
||||
* |
||||
* @author John.Ying |
||||
* @since 11.0 |
||||
* Created on 2023/4/14 |
||||
*/ |
||||
public final class EventDispatchDeveloperMode extends EventQueue { |
||||
|
||||
/** |
||||
* 该链表为主要的实现定时任务的容器,在重写的dispatchEvent中由pre方法将DispatchInfo加入到链表,由post方法remove |
||||
*/ |
||||
private final LinkedList<AwtEventInfo> dispatches = new LinkedList<>(); |
||||
/** |
||||
* 开启间隔检测后两次检测的相隔时间ms |
||||
*/ |
||||
public static final long CHECK_INTERVAL_MS = 5; |
||||
|
||||
private Timer timer; |
||||
|
||||
/** |
||||
* edt事件最大允许的时间 |
||||
*/ |
||||
public static final long MAX_TIME = 20; |
||||
public static final EventDispatchDeveloperMode INSTANCE = new EventDispatchDeveloperMode(); |
||||
|
||||
@Override |
||||
protected void dispatchEvent(AWTEvent event) { |
||||
try { |
||||
preDispatchEvent(event); |
||||
super.dispatchEvent(event); |
||||
} finally { |
||||
postDispatchEvent(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 事件分发前处理 |
||||
*/ |
||||
private synchronized void preDispatchEvent(AWTEvent event) { |
||||
synchronized (dispatches) { |
||||
AwtEventInfo awtEventInfo = new AwtEventInfo(); |
||||
awtEventInfo.setAwtEvent(event); |
||||
dispatches.addLast(awtEventInfo); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 事件分发后处理 |
||||
*/ |
||||
private synchronized void postDispatchEvent() { |
||||
synchronized (dispatches) { |
||||
AwtEventInfo awtEventInfo = dispatches.removeLast(); |
||||
//嵌套最深的事件执行完毕后刷新链表中其他事件的lastDispatchTimeMillis
|
||||
Thread currentEventDispatchThread = Thread.currentThread(); |
||||
for (AwtEventInfo info : dispatches) { |
||||
info.setLastDispatchTimeMillis(System.currentTimeMillis()); |
||||
} |
||||
long nowTime = System.currentTimeMillis(); |
||||
long totalTime = nowTime - awtEventInfo.getStartDispatchTimeMillis(); |
||||
long continuationTime = nowTime - awtEventInfo.getLastDispatchTimeMillis(); |
||||
if (continuationTime > MAX_TIME) { |
||||
FineLoggerFactory.getLogger() |
||||
.warn("awt event spend time more than 20ms, totalTime {} continuationTime {} the stack is {}" |
||||
, totalTime, continuationTime, EventDispatchThreadHangMonitor.stackTraceToStringForConsole(awtEventInfo.getStackTrace())); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 将swing中默认的EventQueue换成自己的 |
||||
*/ |
||||
public void initMonitoring() { |
||||
UIUtil.invokeLaterIfNeeded(() -> Toolkit.getDefaultToolkit().getSystemEventQueue().push(INSTANCE)); |
||||
initTimer(); |
||||
startFilterModalWindow(); |
||||
} |
||||
|
||||
/** |
||||
* Sets up a timer to check for hangs frequently. |
||||
* 初始化一个Timer |
||||
*/ |
||||
public void initTimer() { |
||||
final long initialDelayMs = 0; |
||||
final boolean daemon = true; |
||||
timer = new Timer("EventDispatchDeveloperMode", daemon); |
||||
timer.schedule(new HangChecker(), initialDelayMs, CHECK_INTERVAL_MS); |
||||
} |
||||
|
||||
/** |
||||
* /消除Timer |
||||
*/ |
||||
public void stopTimer() { |
||||
if (timer != null) { |
||||
timer.cancel(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* /定时执行的任务 |
||||
*/ |
||||
public class HangChecker extends TimerTask { |
||||
@Override |
||||
public void run() { |
||||
synchronized (dispatches) { |
||||
//如果链表为空定时检测就不进行
|
||||
if (dispatches.isEmpty()) { |
||||
return; |
||||
} |
||||
dispatches.getLast().checkForHang(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 消除模态框影响 |
||||
*/ |
||||
public void startFilterModalWindow() { |
||||
ScheduledExecutorService scheduledExecutorService = FineExecutors.newSingleThreadScheduledExecutor(); |
||||
scheduledExecutorService.scheduleAtFixedRate(new Runnable() { |
||||
@Override |
||||
public void run() { |
||||
UIUtil.invokeLaterIfNeeded(() -> { |
||||
//不用干事,切个片就可以
|
||||
}); |
||||
} |
||||
}, 0, 10, TimeUnit.MILLISECONDS); |
||||
} |
||||
} |
Loading…
Reference in new issue