如何在java中检测主线程何时冻结GUI?

如何在java中检测主线程何时冻结GUI?,java,swing,cursor,event-dispatch-thread,Java,Swing,Cursor,Event Dispatch Thread,我想检测主线程中的一些耗时操作何时导致gui冻结。 我的目标是自动设置和取消设置等待光标 谢谢我认为您是本末倒置:您的主线程首先不应该执行任何耗时的操作-它们应该始终在单独的线程中外部化,以便您的GUI能够保持响应性(例如,显示操作状态,或提供中止操作的可能性).您可以有一个线程轮询GUI线程的堆栈跟踪,以确定它是空闲还是繁忙。如果太忙,您可以将它正在做的事情(堆栈跟踪)记录到日志中。最初,记录每个非空闲堆栈跟踪并找出哪些不值得记录可能会很有趣。我认为这可能会有所帮助:而且。EDT锁定检测代码将

我想检测主线程中的一些耗时操作何时导致gui冻结。 我的目标是自动设置和取消设置等待光标


谢谢

我认为您是本末倒置:您的主线程首先不应该执行任何耗时的操作-它们应该始终在单独的线程中外部化,以便您的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”标记。如果我错了,请更正我承认我的罪行:显然,设置了诅咒