Java 如何捕获事件调度线程(EDT)异常?

Java 如何捕获事件调度线程(EDT)异常?,java,exception,try-catch,event-dispatch-thread,Java,Exception,Try Catch,Event Dispatch Thread,我正在使用一个名为MyExceptionHandler的类来实现Thread.UncaughtExceptionHandler来处理项目中的正常异常 据我所知,该类无法捕获EDT异常,因此我尝试在main()方法中使用它来处理EDT异常: public static void main( final String[] args ) { Thread.setDefaultUncaughtExceptionHandler( new MyExceptionHandler() ); // Ha

我正在使用一个名为
MyExceptionHandler
的类来实现
Thread.UncaughtExceptionHandler
来处理项目中的正常异常

据我所知,该类无法捕获EDT异常,因此我尝试在
main()
方法中使用它来处理EDT异常:

public static void main( final String[] args ) {
    Thread.setDefaultUncaughtExceptionHandler( new MyExceptionHandler() );  // Handle normal exceptions
    System.setProperty( "sun.awt.exception.handler",MyExceptionHandler.class.getName());  // Handle EDT exceptions
    SwingUtilities.invokeLater(new Runnable() {  // Execute some code in the EDT. 
        public void run() {
            JFrame myFrame = new JFrame();
             myFrame.setVisible( true );
        }
    });
}
但直到现在它还不起作用。例如,在初始化JFrame时,我从构造函数中的捆绑文件加载其标签,如下所示:

setTitle( bundle.getString( "MyJFrame.title" ) );
我从bundle文件中删除了key
MyJFrame.title
,以测试异常处理程序,但它不起作用!异常通常打印在日志中


我在这里做错了什么吗?

EDT异常处理程序没有使用
线程.UncaughtExceptionHandler
。相反,它调用具有以下签名的方法:

public void handle(Throwable thrown);
将它添加到MyExceptionHandler中,它应该可以工作

这方面的“文档”可以在
EventDispatchThread
中找到,它是
java.awt
中的包私有类。从javadoc中引用
handleException()
此处:

/**
 * Handles an exception thrown in the event-dispatch thread.
 *
 * <p> If the system property "sun.awt.exception.handler" is defined, then
 * when this method is invoked it will attempt to do the following:
 *
 * <ol>
 * <li> Load the class named by the value of that property, using the
 *      current thread's context class loader,
 * <li> Instantiate that class using its zero-argument constructor,
 * <li> Find the resulting handler object's <tt>public void handle</tt>
 *      method, which should take a single argument of type
 *      <tt>Throwable</tt>, and
 * <li> Invoke the handler's <tt>handle</tt> method, passing it the
 *      <tt>thrown</tt> argument that was passed to this method.
 * </ol>
 *
 * If any of the first three steps fail then this method will return
 * <tt>false</tt> and all following invocations of this method will return
 * <tt>false</tt> immediately.  An exception thrown by the handler object's
 * <tt>handle</tt> will be caught, and will cause this method to return
 * <tt>false</tt>.  If the handler's <tt>handle</tt> method is successfully
 * invoked, then this method will return <tt>true</tt>.  This method will
 * never throw any sort of exception.
 *
 * <p> <i>Note:</i> This method is a temporary hack to work around the
 * absence of a real API that provides the ability to replace the
 * event-dispatch thread.  The magic "sun.awt.exception.handler" property
 * <i>will be removed</i> in a future release.
 */

这应该就可以了。

只是为了获得一些额外的信息,在许多情况下,即使在1.5和1.6版本中,EDT的UncaughtExceptionHandler也会捕捉到一次性垃圾。查看1.5.022中EventDispatchThread的源代码:

private void processException(Throwable e, boolean isModal) {
    if (!handleException(e)) {
        // See bug ID 4499199.
        // If we are in a modal dialog, we cannot throw
        // an exception for the ThreadGroup to handle (as added
        // in RFE 4063022).  If we did, the message pump of
        // the modal dialog would be interrupted.
        // We instead choose to handle the exception ourselves.
        // It may be useful to add either a runtime flag or API
        // later if someone would like to instead dispose the
        // dialog and allow the thread group to handle it.
        if (isModal) {
            System.err.println(
                "Exception occurred during event dispatching:");
            e.printStackTrace();
        } else if (e instanceof RuntimeException) {
            throw (RuntimeException)e;
        } else if (e instanceof Error) {
            throw (Error)e;
        }
    }
}

private boolean handleException(Throwable thrown) {

    try {

        if (handlerClassName == NO_HANDLER) {
            return false;   /* Already tried, and failed */
        }

        /* Look up the class name */
        if (handlerClassName == null) {
            handlerClassName = ((String) AccessController.doPrivileged(
                new GetPropertyAction(handlerPropName)));
            if (handlerClassName == null) {
                handlerClassName = NO_HANDLER; /* Do not try this again */
                return false;
            }
        }

        /* Load the class, instantiate it, and find its handle method */
        Method m;
        Object h;
        try {
            ClassLoader cl = Thread.currentThread().getContextClassLoader();
            Class c = Class.forName(handlerClassName, true, cl);
            m = c.getMethod("handle", new Class[] { Throwable.class });
            h = c.newInstance();
        } catch (Throwable x) {
            handlerClassName = NO_HANDLER; /* Do not try this again */
            return false;
        }

        /* Finally, invoke the handler */
        m.invoke(h, new Object[] { thrown });

    } catch (Throwable x) {
        return false;
    }

    return true;
}
根据这段代码,EDT线程的UncaughtExceptionHandler只有3种方式不会捕获可丢弃文件:

  • Throwable由sun.awt.exception.handler成功处理(找到并实例化了类,调用了它的handle(Throwable)方法,但没有抛出任何内容)
  • EDT处于模式对话框中
  • Throwable既不是RuntimeException,也不是错误

  • 综上所述。。。使用较新的Java,您只需执行以下操作:

    // Log exceptions thrown on the event dispatcher thread
    SwingUtilities.invokeLater(()
      -> Thread.currentThread().setUncaughtExceptionHandler((thread, t)
      -> this.log.error("exception in event dispatcher thread", t)));
    

    @乌克尔曼。。。我照你说的做了,但没有发现异常情况。。。public void handle(Throwable抛出){System.out.println(“捕获异常”);//dod bot print!}@Brad:“即使句柄(…)不存在,异常也将由实现的方法uncaughtException(…)处理,那么就不需要句柄(…)!”这是错误的。EDT上的未捕获异常永远不会转到线程。未捕获异常处理程序,因为EDT不是常规线程。如果您的异常在示例中的异常处理程序中都没有采用这两条路径,那么您就没有未捕获的异常——它正在某个地方被捕获。@uckelman。。。在调查了我的密码后,你是对的。我代码中的一部分捕获了EDT异常。但是对于handle(…)方法,它不是必需的。仅设置系统属性就足够了:system.setProperty(“sun.awt.exception.handler”,MyExceptionHandler.class.getName())。。。我敢肯定。我已经创建了一个完整的样本来测试它。你也可以试试这个。非常感谢您的帮助。@Brad:我想自从上次查看以来,
    java.awt.EventDispatchThread
    中发生了一些变化,即,
    processException()
    如果
    handleException()
    返回false,则返回异常,如果您没有
    handle()
    方法,该方法位于使用
    sun.awt.exception.handler
    属性指定的处理程序中。因此,至少在Java 6的当前版本中,我想您可以只使用
    线程.UncaughtExceptionHandler
    。知道这一点很好,但在旧版本的Java中可能无法正常工作。我可以确认在Java7中不需要
    handle()
    方法,我们也无法在Javadoc中找到它的任何痕迹。多亏了你们两位,我现在可以正确地记录未捕获的异常了!:)但是,异常跟踪仍在stderr上打印。有没有办法避免这种情况?可能的重复
    // Log exceptions thrown on the event dispatcher thread
    SwingUtilities.invokeLater(()
      -> Thread.currentThread().setUncaughtExceptionHandler((thread, t)
      -> this.log.error("exception in event dispatcher thread", t)));