如何在java中检测主线程何时冻结GUI?
我想检测主线程中的一些耗时操作何时导致gui冻结。 我的目标是自动设置和取消设置等待光标如何在java中检测主线程何时冻结GUI?,java,swing,cursor,event-dispatch-thread,Java,Swing,Cursor,Event Dispatch Thread,我想检测主线程中的一些耗时操作何时导致gui冻结。 我的目标是自动设置和取消设置等待光标 谢谢我认为您是本末倒置:您的主线程首先不应该执行任何耗时的操作-它们应该始终在单独的线程中外部化,以便您的GUI能够保持响应性(例如,显示操作状态,或提供中止操作的可能性).您可以有一个线程轮询GUI线程的堆栈跟踪,以确定它是空闲还是繁忙。如果太忙,您可以将它正在做的事情(堆栈跟踪)记录到日志中。最初,记录每个非空闲堆栈跟踪并找出哪些不值得记录可能会很有趣。我认为这可能会有所帮助:而且。EDT锁定检测代码将
谢谢我认为您是本末倒置:您的主线程首先不应该执行任何耗时的操作-它们应该始终在单独的线程中外部化,以便您的GUI能够保持响应性(例如,显示操作状态,或提供中止操作的可能性).您可以有一个线程轮询GUI线程的堆栈跟踪,以确定它是空闲还是繁忙。如果太忙,您可以将它正在做的事情(堆栈跟踪)记录到日志中。最初,记录每个非空闲堆栈跟踪并找出哪些不值得记录可能会很有趣。我认为这可能会有所帮助:而且。EDT锁定检测代码将通过添加看门狗来完成这项工作
EventQueueWithWD.java
:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
/**
* Alternative events dispatching queue. The benefit over the
* default Event Dispatch queue is that you can add as many
* watchdog timers as you need and they will trigger arbitrary
* actions when processing of single event will take longer than
* one timer period.
* <p/>
* Timers can be of two types:
* <ul>
* <li><b>Repetitive</b> - action can be triggered multiple times
* for the same "lengthy" event dispatching.
* </li>
* <li><b>Non-repetitive</b> - action can be triggered only once
* per event dispatching.</li>
* </ul>
* <p/>
* The queue records time of the event dispatching start. This
* time is used by the timers to check if dispatching takes
* longer than their periods. If so the timers trigger associated
* actions.
* <p/>
* In order to use this queue application should call
* <code>install()</code> method. This method will create,
* initialize and register the alternative queue as appropriate.
* It also will return the instance of the queue for further
* interactions. Here's an example of how it can be done:
* <p/>
* <pre>
* <p/>
* EventQueueWithWD queue = EventQueueWithWD.install();
* Action edtOverloadReport = ...;
* <p/>
* // install single-shot wg to report EDT overload after
* // 10-seconds timeout
* queue.addWatchdog(10000, edtOverloadReport, false);
* <p/>
* </pre>
*/
public class EventQueueWithWD extends EventQueue {
// Main timer
private final java.util.Timer timer = new java.util.Timer(true);
// Group of informational fields for describing the event
private final Object eventChangeLock = new Object();
private volatile long eventDispatchingStart = -1;
private volatile AWTEvent event = null;
/**
* Hidden utility constructor.
*/
private EventQueueWithWD() { }
/**
* Install alternative queue.
*
* @return instance of queue installed.
*/
public static EventQueueWithWD install() {
EventQueue eventQueue =
Toolkit.getDefaultToolkit().getSystemEventQueue();
EventQueueWithWD newEventQueue = new EventQueueWithWD();
eventQueue.push(newEventQueue);
return newEventQueue;
}
/**
* Record the event and continue with usual dispatching.
*
* @param anEvent event to dispatch.
*/
protected void dispatchEvent(AWTEvent anEvent) {
setEventDispatchingStart(anEvent, System.currentTimeMillis());
super.dispatchEvent(anEvent);
setEventDispatchingStart(null, -1);
}
/**
* Register event and dispatching start time.
*
* @param anEvent event.
* @param timestamp dispatching start time.
*/
private void setEventDispatchingStart(AWTEvent anEvent,
long timestamp) {
synchronized (eventChangeLock) {
event = anEvent;
eventDispatchingStart = timestamp;
}
}
/**
* Add watchdog timer. Timer will trigger <code>listener</code>
* if the queue dispatching event longer than specified
* <code>maxProcessingTime</code>. If the timer is
* <code>repetitive</code> then it will trigger additional
* events if the processing 2x, 3x and further longer than
* <code>maxProcessingTime</code>.
*
* @param maxProcessingTime maximum processing time.
* @param listener listener for events. The listener
* will receive <code>AWTEvent</code>
* as source of event.
* @param repetitive TRUE to trigger consequent events
* for 2x, 3x and further periods.
*/
public void addWatchdog(long maxProcessingTime,
ActionListener listener,
boolean repetitive) {
Watchdog checker = new Watchdog(maxProcessingTime, listener,
repetitive);
timer.schedule(checker, maxProcessingTime,
maxProcessingTime);
}
/**
* Checks if the processing of the event is longer than the
* specified <code>maxProcessingTime</code>. If so then
* listener is notified.
*/
private class Watchdog extends TimerTask {
// Settings
private final long maxProcessingTime;
private final ActionListener listener;
private final boolean repetitive;
// Event reported as "lengthy" for the last time. Used to
// prevent repetitive behaviour in non-repeatitive timers.
private AWTEvent lastReportedEvent = null;
/**
* Creates timer.
*
* @param maxProcessingTime maximum event processing time
* before listener is notified.
* @param listener listener to notify.
* @param repetitive TRUE to allow consequent
* notifications for the same event
*/
private Watchdog(long maxProcessingTime,
ActionListener listener,
boolean repetitive) {
if (listener == null)
throw new IllegalArgumentException(
"Listener cannot be null.");
if (maxProcessingTime < 0)
throw new IllegalArgumentException(
"Max locking period should be greater than zero");
this.maxProcessingTime = maxProcessingTime;
this.listener = listener;
this.repetitive = repetitive;
}
public void run() {
long time;
AWTEvent currentEvent;
// Get current event requisites
synchronized (eventChangeLock) {
time = eventDispatchingStart;
currentEvent = event;
}
long currentTime = System.currentTimeMillis();
// Check if event is being processed longer than allowed
if (time != -1 && (currentTime - time > maxProcessingTime) &&
(repetitive || currentEvent != lastReportedEvent)) {
listener.actionPerformed(
new ActionEvent(currentEvent, -1, null));
lastReportedEvent = currentEvent;
}
}
}
}
*/
公共类EventQueueWithWD扩展了EventQueue{
//主定时器
private final java.util.Timer Timer=new java.util.Timer(true);
//用于描述事件的信息字段组
私有最终对象eventChangeLock=新对象();
private volatile long events dispatchingstart=-1;
私有易失性AWTEvent事件=null;
/**
*隐藏的实用程序构造函数。
*/
私有EventQueueWithWD(){}
/**
*安装备用队列。
*
*@已安装队列的返回实例。
*/
公共静态事件队列WithWD安装(){
事件队列事件队列=
Toolkit.getDefaultToolkit().getSystemEventQueue();
EventQueueWithWD newEventQueue=新的EventQueueWithWD();
推送(newEventQueue);
返回newEventQueue;
}
/**
*记录事件并继续进行常规调度。
*
*@param要分派的事件。
*/
受保护的无效调度事件(AWTEvent anEvent){
setEventDispatchingStart(anEvent,System.currentTimeMillis());
超级调度事件(anEvent);
setEventDispatchingStart(null,-1);
}
/**
*注册事件和调度开始时间。
*
*@param-anEvent事件。
*@param timestamp调度开始时间。
*/
私有void setEventDispatchingStart(AWTEvent anEvent,
长时间戳){
已同步(eventChangeLock){
事件=事件;
eventDispatchingStart=时间戳;
}
}
/**
*添加看门狗定时器。定时器将触发监听器
*如果队列调度事件长于指定的时间
*maxProcessingTime
。如果计时器
*重复
则会触发额外的
*如果处理时间为2倍、3倍或更长,则会发生事件
*maxProcessingTime
。
*
*@param maxProcessingTime最大处理时间。
*@param listener事件的侦听器。侦听器
*将收到AWTEvent
*作为事件的源头。
*@param repeative TRUE触发后续事件
*2倍、3倍及更长时间。
*/
public void addWatchdog(长最大处理时间,
ActionListener,listener,
布尔(重复){
看门狗检查器=新看门狗(maxProcessingTime,listener,
重复);
timer.schedule(checker,maxProcessingTime,
最大处理时间);
}
/**
*检查事件的处理时间是否长于
*指定的maxProcessingTime
。如果是,则
*将通知侦听器。
*/
私有类看门狗扩展TimerTask{
//背景
私有最终长最大处理时间;
私人最终行动听者;
私有最终布尔重复;
//上次报告为“冗长”的事件。用于
//防止非重复计时器中的重复行为。
私有AWTEvent lastReportedEvent=null;
/**
*创建计时器。
*
*@param maxProcessingTime最大事件处理时间
*在通知听者之前。
*@param listener要通知的侦听器。
*@param repeative TRUE允许后续
*同一事件的通知
*/
私人看门狗(长最大处理时间,
ActionListener,listener,
布尔(重复){
if(侦听器==null)
抛出新的IllegalArgumentException(
“侦听器不能为空。”);
如果(最大处理时间<0)
抛出新的IllegalArgumentException(
“最大锁定周期应大于零”);
this.maxProcessingTime=maxProcessingTime;
this.listener=listener;
这是重复的;
}
公开募捐{
长时间;
AWTEvent事件;
//获取当前事件必备项
已同步(eventChangeLock){
时间=eventDispatchingStart;
currentEvent=事件;
}
长currentTime=System.currentTimeMillis();
//检查事件处理的时间是否超过允许的时间
如果(时间!=-1&&(currentTime-time>maxProcessingTime)&&
(重复的| | currentEvent!=上次报告的事件)){
listener.actionPerformed(
新的ActionEvent(currentEvent,-1,null));
lastReportedEvent=currentEvent;
}
}
}
}
sampleequage.java
:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
/**
* Alternative events dispatching queue. The benefit over the
* default Event Dispatch queue is that you can add as many
* watchdog timers as you need and they will trigger arbitrary
* actions when processing of single event will take longer than
* one timer period.
* <p/>
* Timers can be of two types:
* <ul>
* <li><b>Repetitive</b> - action can be triggered multiple times
* for the same "lengthy" event dispatching.
* </li>
* <li><b>Non-repetitive</b> - action can be triggered only once
* per event dispatching.</li>
* </ul>
* <p/>
* The queue records time of the event dispatching start. This
* time is used by the timers to check if dispatching takes
* longer than their periods. If so the timers trigger associated
* actions.
* <p/>
* In order to use this queue application should call
* <code>install()</code> method. This method will create,
* initialize and register the alternative queue as appropriate.
* It also will return the instance of the queue for further
* interactions. Here's an example of how it can be done:
* <p/>
* <pre>
* <p/>
* EventQueueWithWD queue = EventQueueWithWD.install();
* Action edtOverloadReport = ...;
* <p/>
* // install single-shot wg to report EDT overload after
* // 10-seconds timeout
* queue.addWatchdog(10000, edtOverloadReport, false);
* <p/>
* </pre>
*/
public class EventQueueWithWD extends EventQueue {
// Main timer
private final java.util.Timer timer = new java.util.Timer(true);
// Group of informational fields for describing the event
private final Object eventChangeLock = new Object();
private volatile long eventDispatchingStart = -1;
private volatile AWTEvent event = null;
/**
* Hidden utility constructor.
*/
private EventQueueWithWD() { }
/**
* Install alternative queue.
*
* @return instance of queue installed.
*/
public static EventQueueWithWD install() {
EventQueue eventQueue =
Toolkit.getDefaultToolkit().getSystemEventQueue();
EventQueueWithWD newEventQueue = new EventQueueWithWD();
eventQueue.push(newEventQueue);
return newEventQueue;
}
/**
* Record the event and continue with usual dispatching.
*
* @param anEvent event to dispatch.
*/
protected void dispatchEvent(AWTEvent anEvent) {
setEventDispatchingStart(anEvent, System.currentTimeMillis());
super.dispatchEvent(anEvent);
setEventDispatchingStart(null, -1);
}
/**
* Register event and dispatching start time.
*
* @param anEvent event.
* @param timestamp dispatching start time.
*/
private void setEventDispatchingStart(AWTEvent anEvent,
long timestamp) {
synchronized (eventChangeLock) {
event = anEvent;
eventDispatchingStart = timestamp;
}
}
/**
* Add watchdog timer. Timer will trigger <code>listener</code>
* if the queue dispatching event longer than specified
* <code>maxProcessingTime</code>. If the timer is
* <code>repetitive</code> then it will trigger additional
* events if the processing 2x, 3x and further longer than
* <code>maxProcessingTime</code>.
*
* @param maxProcessingTime maximum processing time.
* @param listener listener for events. The listener
* will receive <code>AWTEvent</code>
* as source of event.
* @param repetitive TRUE to trigger consequent events
* for 2x, 3x and further periods.
*/
public void addWatchdog(long maxProcessingTime,
ActionListener listener,
boolean repetitive) {
Watchdog checker = new Watchdog(maxProcessingTime, listener,
repetitive);
timer.schedule(checker, maxProcessingTime,
maxProcessingTime);
}
/**
* Checks if the processing of the event is longer than the
* specified <code>maxProcessingTime</code>. If so then
* listener is notified.
*/
private class Watchdog extends TimerTask {
// Settings
private final long maxProcessingTime;
private final ActionListener listener;
private final boolean repetitive;
// Event reported as "lengthy" for the last time. Used to
// prevent repetitive behaviour in non-repeatitive timers.
private AWTEvent lastReportedEvent = null;
/**
* Creates timer.
*
* @param maxProcessingTime maximum event processing time
* before listener is notified.
* @param listener listener to notify.
* @param repetitive TRUE to allow consequent
* notifications for the same event
*/
private Watchdog(long maxProcessingTime,
ActionListener listener,
boolean repetitive) {
if (listener == null)
throw new IllegalArgumentException(
"Listener cannot be null.");
if (maxProcessingTime < 0)
throw new IllegalArgumentException(
"Max locking period should be greater than zero");
this.maxProcessingTime = maxProcessingTime;
this.listener = listener;
this.repetitive = repetitive;
}
public void run() {
long time;
AWTEvent currentEvent;
// Get current event requisites
synchronized (eventChangeLock) {
time = eventDispatchingStart;
currentEvent = event;
}
long currentTime = System.currentTimeMillis();
// Check if event is being processed longer than allowed
if (time != -1 && (currentTime - time > maxProcessingTime) &&
(repetitive || currentEvent != lastReportedEvent)) {
listener.actionPerformed(
new ActionEvent(currentEvent, -1, null));
lastReportedEvent = currentEvent;
}
}
}
}
这没有多大意义。如果gui被冻结,您将无法设置等待光标:gui被冻结。@blow有可能提取Event Dispash线程中的所有事件,检查违反情况,对于Reapaint Manager,但为什么??,您必须计算(如果我们讨论的是AWT、Swing及其派生)EDT中的所有事件都将完成(输出到屏幕)片刻之后,@blow:添加了“swing”标记。如果我错了,请更正我承认我的罪行:显然,设置了诅咒