John.Ying-应志浩
2 years ago
3 changed files with 5 additions and 284 deletions
@ -1,73 +0,0 @@ |
|||||||
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; |
|
||||||
} |
|
||||||
} |
|
@ -1,141 +0,0 @@ |
|||||||
package com.fr.design.carton.developer; |
|
||||||
|
|
||||||
|
|
||||||
import com.aspose.words.Run; |
|
||||||
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 static final int CORE_THREAD_SIZE = 1; |
|
||||||
|
|
||||||
private ScheduledExecutorService 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(); |
|
||||||
//判断连续执行时间是否超过了20ms,超过了则进行提示
|
|
||||||
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; |
|
||||||
timer = FineExecutors.newScheduledThreadPool(CORE_THREAD_SIZE); |
|
||||||
timer.schedule(() -> { |
|
||||||
synchronized (dispatches) { |
|
||||||
//如果链表为空定时检测就不进行
|
|
||||||
if (dispatches.isEmpty()) { |
|
||||||
return; |
|
||||||
} |
|
||||||
dispatches.getLast().checkForHang(); |
|
||||||
} |
|
||||||
}, initialDelayMs, TimeUnit.MILLISECONDS); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* /消除Timer |
|
||||||
*/ |
|
||||||
public void stopTimer() { |
|
||||||
if (timer != null) { |
|
||||||
timer.shutdown(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 消除模态框影响 |
|
||||||
*/ |
|
||||||
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