【问题标题】:Debug exceptions in AWT queue thread调试 AWT 队列线程中的异常
【发布时间】:2015-02-20 14:11:23
【问题描述】:

我正在开发一个带有执行自定义绘画的组件的 Swing 应用程序。当我在绘制代码中出现错误并抛出异常时,情况很难调试。不会被调试器捕获,而是会显示一个带有异常信息的弹出窗口。而且the thread seems to be restarted,由于异常是编码错误,所以反复显示。

当我有幸切换到调试器时(这很困难,因为随着应用程序获取绘制请求,越来越多的弹出窗口不断出现),调试控制台向我显示异常信息,例如:

严重:线程中抛出未捕获的异常[AWT-EventQueue-0,6,main]

....堆栈跟随

我的应用程序是用 Scala 编写的,我使用的是 IntelliJ IDEA 14。调试器可以很好地处理我未捕获的主线程异常(我在 Any exception 中启用了 Uncaught exception 断点Java Exception Breakpoints),但有异常在 AWT 线程中不是。

我已尝试按照this How can I detect when an Exception's been thrown globally in Java? answer 中的说明安装处理程序,但我的处理程序似乎没有被触发。

我想实现以下目标(按重要性排序):

  1. 避免 AWT 线程在异常时重新启动,或者至少防止弹出窗口显示
  2. 在调试器中处理未捕获的异常,而不是在控制台中打印

(注意:虽然这是 Scala 应用程序,但我假设 Java 的行为是相同的,因此是 Java 标记)。

【问题讨论】:

  • 您提到异常是在绘画中引发的。你确定吗?如果没有堆栈跟踪,就很难回答这个问题。但是,如果您知道异常来自哪里,您就不能分析代码中的错误,添加异常处理。基于异常的行上的条件断点应该会有所帮助。

标签: java scala debugging intellij-idea awt


【解决方案1】:

根据这个link,您必须同时处理常规ExceptionEDT Exception,而不使用旧的sun.awt.exception.handler hack(自Java 7 起不再适用)

这是你的ExceptionHandler

public static class ExceptionHandler implements Thread.UncaughtExceptionHandler
{
    public void uncaughtException(Thread thread, Throwable thrown)
    {
        // TODO handle your Exception here
    }
}

用法:

// Regular Exception
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler());

// EDT Exception
SwingUtilities.invokeAndWait(new Runnable()
{
    public void run()
    {
        // We are in the event dispatching thread
        Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler());
    }
});

【讨论】:

  • 太好了,谢谢 - 这就是我所缺少的。您是否会碰巧知道(或能够了解)为什么 setDefaultUncaughtExceptionHandler 对于 EDT 来说是不够的?它有自己的某种处理程序吗?还是 setDefaultUncaughtExceptionHandler 不适用于已经启动的线程?您链接的文章很好,但似乎没有解释这一点。
  • 我不知道。不过问题很好:)
  • 暂时接受,但仍在等待赏金,也许有人会提供更多细节。
  • 你的问题让我进一步推动了我的调查。事实上,根据EventDispatchThread source codegetDefaultUncaughtExceptionHandler 从未在EventDispatchThread 中使用。相反,getUncaughtExceptionHandler() 在方法processException 中被显式调用。这就解释了为什么 setDefaultUncaughtExceptionHandler 还不够。
  • 只有一个 EDT。我们是否需要调用 Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler());每次我们使用 invokeAndWait() 和 invokeLater() ?
【解决方案2】:

在 Java 中

您的问题是在另一个线程中引发了异常,即事件调度线程。几个解决方案:

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
    public void uncaughtException(Thread t, Throwable e) {
        logger.error("Uncaught exception in thread: " + t.getName, e);
    }
});

在任何情况下,您原则上都应该将您的 UI 启动代码放在一个

EventQueue.invokeLater();

或者直接调用这个的SwingUtilities.invokeLater()

在 Scala 中

您的问题是在另一个线程中引发了异常,即事件调度线程。几个解决方案:

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
  def uncaughtException(t: Thread, e: Throwable) {
    logger.error("Uncaught exception in thread: " + t.getName, e)
  }
})

在任何情况下,您原则上都应该将您的 UI 启动代码放在一个

EventQueue.invokeLater()

【讨论】:

  • 简单来说回答你的2个问题,使用EventQueue,如果你想查看其他线程异常设置默认的未捕获异常处理程序。
  • 正如我在问题中所写,stackoverflow.com/questions/27603348/… 中所述安装的处理程序不会触发我。应该是?答案很老了,还有效吗?
  • 我不明白 EventQueue 与我的问题有何关系 - 它如何影响异常处理?我说的是paintComponent的异常,它已经在EDT中执行了——我应该在这里用EventQueue做什么?
  • EventQueue - 虽然异常可能来自 EDT,但可能是其他东西正在访问另一个线程中的资源导致错误,例如修改一个列表,应该在 EDT 上执行。根据现有信息,这似乎是试图回答这个问题的一个原因,可惜它被否决了。
【解决方案3】:

看起来您唯一的解决方案可能是切换到 Eclipse。 :-) 其他解决方案需要编码工作,并且在异常处理程序中停止与在引发异常的确切位置停止不同。

使用以下程序,我可以毫无问题地在 Eclipse 中侦听捕获/未捕获的 RuntimeException 实例。

package lambda;

import java.awt.Dimension;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class AWTExceptionTest {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JButton button = new JButton("Test");
        button.addActionListener(e -> { throw new RuntimeException(); });
        frame.add(button);
        frame.setSize(new Dimension(50, 50));
        SwingUtilities.invokeLater(() -> frame.setVisible(true));
    }
}

这是它在 Eclipse 中调试模式下的外观。

【讨论】:

  • 我看到你在 RuntimeException 上设置了 Caught 和 Uncaught 的断点。这可以在任何 IDE 中完成,但它捕获的太多 - 甚至是代码可以很好地处理的异常。
  • @Suma 好吧,我有它,因为我是这样设置的。在 Eclipse 中,将其配置为只侦听未捕获的异常是没有问题的。
  • 这与 IntelliJ 相同,因此迁移到 Eclipse 不太可能在这方面对我有所帮助。恐怕如果您尝试一下,您会发现 EDT 异常并非未处理。 :(
  • @Suma 你是对的。看起来所有异常都在 EDT 中捕获。我认为线程中有一个很大的 try 块可以捕获 Throwable 的所有实例,因此它不会死,因此不必重新启动。如果我发现了什么,我会寻找另一个解决方案并相应地更新答案。
  • 这与我所看到的一致。令我惊讶的是,按照 ToYonos 的回答中所述安装 setUncaughtExceptionHandler 是可行的。看源码,是因为pumpOneEventForFilters在你提到的大try块的catch中调用了getUncaughtExceptionHandler().uncaughtException(通过processException)。我可以在处理程序中放置断点,但这并不理想,因为调试器不会在抛出异常时停止,而是只有在异常被 EDT 捕获并传递给处理程序后才会停止。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-10
  • 2011-07-02
  • 2013-04-28
  • 2015-10-23
相关资源
最近更新 更多