【问题标题】:Does the EDT restart or not when an exception is thrown?抛出异常时 EDT 是否重新启动?
【发布时间】:2016-01-14 03:38:17
【问题描述】:

(下面的示例代码是独立且可运行的,你可以试试,它不会让你的系统崩溃:)

Tom Hawtin 在这里评论了这个问题:Why do people run Java GUI's on the Event Queue

那个:

EDT 不太可能崩溃。在 EDT 调度中抛出的未经检查的异常被捕获、转储并且线程继续运行。

谁能解释一下这里发生了什么(每次您点击“抛出未经检查的异常”按钮时,都会故意除以零):

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class CrashEDT extends JFrame {

    public static void main(String[] args) {
        final CrashEDT frame = new CrashEDT();
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing( WindowEvent e) {
                System.exit(0);
            }
        });
        final JButton jb = new JButton( "throw an unchecked exception" );
        jb.addActionListener( new ActionListener() {
            public void actionPerformed( ActionEvent e ) {
                System.out.println( "Thread ID:" + Thread.currentThread().getId() );
                System.out.println( 0 / Math.abs(0) );
            }
        } );
        frame.add( jb );
        frame.setSize(300, 150);
        frame.setVisible(true);
    }

}

我收到以下消息(这是我所期望的):

Exception in thread "AWT-EventQueue-0" java.lang.ArithmeticException: / by zero

对我来说这是一个未经检查的异常,对吧?

您可以看到每次触发崩溃时线程 ID 都会增加。

所以每次抛出未经检查的异常或未经检查的异常“捕获、转储和线程继续”时,EDT 会自动重启吗? 就像 Tom Hawtin 评论的那样?

这是怎么回事?

【问题讨论】:

  • 关于完全不同的问题的一个有趣的旁注:您不必执行 Math.abs(0) 来“欺骗”编译器来接受它。 0/0 是一个好的表达式,也会抛出异常。 read more...
  • @aioobe:嘿嘿,我知道,我知道,我读过那个讨论......但如果写成 0/0 或 1/0,那么人们会问它是什编译:)
  • 哈哈哈...好点 :-)
  • EventDispatchThread.pumpOneEventForFilters,在当前的实现中“很复杂”。显然,不同的实现可能会有所不同。在没有实现的窗口时 EDT 退出之前,可能总是会捕获异常。

标签: java exception event-dispatch-thread


【解决方案1】:

有趣的问题。我会认为异常被捕获并且线程继续,但经过一些研究我不太确定。

我用一个扩展了你的程序

Set<Thread> seenAwtThreads = new HashSet<Thread>();

其中我收集了所有“看到的”awt 线程,并且每次单击“抛出异常”按钮时集合的大小都会增加,这似乎表明在发生异常时会初始化一个新线程。

最后我在EventDispatchThreadrun实现中找到了这条评论:

/*
 * Event dispatch thread dies in case of an uncaught exception. 
 * A new event dispatch thread for this queue will be started
 * only if a new event is posted to it. In case if no more
 * events are posted after this thread died all events that 
 * currently are in the queue will never be dispatched.
 */

完整的run方法的实现如下:

public void run() {
    try {
        pumpEvents(new Conditional() {
            public boolean evaluate() {
                return true;
            }
        });     
    } finally {
        /*
         * This synchronized block is to secure that the event dispatch 
         * thread won't die in the middle of posting a new event to the
         * associated event queue. It is important because we notify
         * that the event dispatch thread is busy after posting a new event
         * to its queue, so the EventQueue.dispatchThread reference must
         * be valid at that point.
         */
        synchronized (theQueue) {
            if (theQueue.getDispatchThread() == this) {
                theQueue.detachDispatchThread();
            }
            /*
             * Event dispatch thread dies in case of an uncaught exception. 
             * A new event dispatch thread for this queue will be started
             * only if a new event is posted to it. In case if no more
             * events are posted after this thread died all events that 
             * currently are in the queue will never be dispatched.
             */
            /*
             * Fix for 4648733. Check both the associated java event
             * queue and the PostEventQueue.
             */
            if (theQueue.peekEvent() != null || 
                !SunToolkit.isPostEventQueueEmpty()) { 
                theQueue.initDispatchThread();
            }
            AWTAutoShutdown.getInstance().notifyThreadFree(this);
        }
    }
}

【讨论】:

  • @NoozNooz42,不,我认为是 6。如果您发现它在 java 7 中发生了变化,请告诉我 :-)
  • 抱歉回复延迟。我在 Mac OS X 10.5.8 和 Ubuntu 10.04 上都使用了 Java 1.6。 Mac 源代码与您显示的相同。
【解决方案2】:

作为参考,“this machinery 的特定行为取决于实现。”例如,线程 ID 在我的平台上保持不变。在AWT Threading Issues 中讨论的最终效果是“当至少有一个可显示组件时,JVM 不会退出。”

【讨论】:

  • @trashgod:到目前为止,我只在 Debian Linux 系统上尝试过 :) +1,java.sun.com/javase/6/docs/api/java/awt/doc-files/… 链接非常棒!
  • 是的。我在 ubuntu 上使用 java 6。你在垃圾神上是哪个系统?
  • @NoozNooz42:虽然 Mac OS X 保持相同的 ID,但我看到你在 Ubuntu 10.04 上报告的递增。
  • @trashgod:是的,刚刚在 OS X 10.4 / Tiger / Java 1.5 和 OS X 10.6 / Snow Leopard / Java 1.6 上进行了尝试,并且两者的 ID 都保持不变。我 认为 在 OS X 上,按钮释放后按钮未正确重绘(崩溃后,就像鼠标释放事件丢失一样),而在 Linux 上,按钮释放被正确考虑(不确实如此)。
  • @NoozNooz42:我在 Mac OS X 10.5.8 和 Ubuntu 10.04 上都使用了 Java 1.6。 eMac 源与@aioobe 显示的相同。
【解决方案3】:

在 Event Dispatch Thread 上设置了默认的UncaughtExceptionHandler,它将异常打印到 System.out,然后在线程中继续。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-23
    • 1970-01-01
    • 2013-01-30
    • 2012-06-28
    • 1970-01-01
    • 2011-10-11
    • 1970-01-01
    • 2014-03-14
    相关资源
    最近更新 更多