Browse Source

REPORT-83195 卡顿点优化-开发者模式

feature/x
John.Ying-应志浩 1 year ago
parent
commit
808f940df2
  1. 74
      designer-base/src/main/java/com/fr/design/carton/SwitchForSwingChecker.java
  2. 73
      designer-base/src/main/java/com/fr/design/carton/developer/AwtEventInfo.java
  3. 146
      designer-base/src/main/java/com/fr/design/carton/developer/EventDispatchDeveloperMode.java

74
designer-base/src/main/java/com/fr/design/carton/SwitchForSwingChecker.java

@ -1,6 +1,7 @@
package com.fr.design.carton;
import com.fr.design.carton.developer.EventDispatchDeveloperMode;
import com.fr.design.i18n.Toolkit;
import com.fr.general.GeneralUtils;
import com.fr.json.JSON;
@ -29,11 +30,22 @@ import java.util.Map;
import java.util.Date;
import java.util.Calendar;
public class SwitchForSwingChecker implements XMLReadable, XMLWriter {
/**
* Designer4Debug类名
*/
private static final String DEBUG_MAIN_CLASS_NAME = "com.fr.start.Designer4Debug";
/**
* 真正主类
*/
private static final String NORMAL_MAIN_CLASS_NAME = "com.fr.start.MainDesigner";
/**
* 开发者模式jvm参数
*/
private static final String CARTON_DEVELOPER_JVM_PARAM = "cartonDeveloper";
/**
* XML标签
*/
@ -249,11 +261,7 @@ public class SwitchForSwingChecker implements XMLReadable, XMLWriter {
*/
public static void initThreadMonitoring () {
String mainClass = System.getProperty("sun.java.command");
//判断一下,如果是以Designer4Debug启动,就不注册代码,不然会覆盖掉SwingExplorer,导致其无法使用
if (!StringUtils.equals(mainClass, DEBUG_MAIN_CLASS_NAME)) {
EventDispatchThreadHangMonitor.initMonitoring();
AppContext.getAppContext().put(SwingWorker.class, CartonThreadExecutorPool.getTimerThreadExecutorPool());
}
MainClassType.getMainClassType(mainClass).initEventQueue();
}
/**
@ -309,4 +317,60 @@ public class SwitchForSwingChecker implements XMLReadable, XMLWriter {
writer.end();
}
/**
* 根据程序启动类路径进行区分
*
* @author John.Ying
* @since 11.0
* Created on 2023/4/14
*/
enum MainClassType {
/**
* 用mainDesigner启动
*/
MAIN(NORMAL_MAIN_CLASS_NAME) {
@Override
void initEventQueue() {
if (StringUtils.equals("true", System.getProperty(CARTON_DEVELOPER_JVM_PARAM))) {
EventDispatchDeveloperMode.INSTANCE.initMonitoring();
} else {
EventDispatchThreadHangMonitor.initMonitoring();
AppContext.getAppContext().put(SwingWorker.class, CartonThreadExecutorPool.getTimerThreadExecutorPool());
}
}
},
/**
* designer4debug启动
*/
DEBUG_MAIN(DEBUG_MAIN_CLASS_NAME) {
@Override
void initEventQueue() {
}
};
MainClassType(String classPath) {
this.classPath = classPath;
}
String classPath;
/**
* 初始化重写的EDT
*/
abstract void initEventQueue();
/**
* @param classPath 启动类路径
*/
static MainClassType getMainClassType(String classPath) {
for (MainClassType mainClassType : MainClassType.values()) {
if (StringUtils.equals(classPath, mainClassType.classPath)) {
return mainClassType;
}
}
return MAIN;
}
}
}

73
designer-base/src/main/java/com/fr/design/carton/developer/AwtEventInfo.java

@ -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;
}
}

146
designer-base/src/main/java/com/fr/design/carton/developer/EventDispatchDeveloperMode.java

@ -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…
Cancel
Save