【问题标题】:How do you use the Event Dispatch Thread?你如何使用事件调度线程?
【发布时间】:2011-12-15 08:28:15
【问题描述】:

我了解到 swing 不是线程安全的。深入研究后,我发现对 Swing 组件的每次修改都必须在 Event Dispatch Thread 上完成,以防止与多线程相关的各种问题。然而,信息似乎完全停在那里。似乎没有一个很好的教程来解释如何在 Internet 上任何可访问的地方执行此操作。

将与其他问题相关的代码中的信息拼凑在一起,似乎我必须在我的程序中的每一个摆动修改周围放置一个不整洁的代码块(就像我自己的代码中的这个示例):

try {
        SwingUtilities.invokeAndWait(new Runnable() {

            public void run() {
                setTitle("Frame title");
                setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                setVisible(true);

                setSize(800, 480);
                setLocationRelativeTo(null);
                setIconImage(Toolkit.getDefaultToolkit().createImage(ClassLoader.getSystemResource("Frame icon.png")));
            }
        });
    } catch (Exception e) {
        e.printStackTrace();
    }

基本上,这是对的吗?我是否必须在代码中对 Swing 组件的每次修改都添加该代码(或与 invokeLater 等效的代码)?

另外,为什么 Swing 不自动执行此操作?

【问题讨论】:

    标签: java swing thread-safety event-dispatch-thread


    【解决方案1】:

    并非所有 UI 代码都必须是 invokeLater 调用中可运行的一部分。这仅仅是因为你的程序的很大一部分无论如何都将在 EDT 上运行。仅当您在不同的线程上时,您才需要向 EDT 发送消息。

    【讨论】:

      【解决方案2】:

      请注意,从事件处理程序执行的任何代码都已在 EDT(首字母缩写词中的事件)中运行

      这意味着对于一般用途(虽然你不会与 swingworkers 和线程池等混淆)你总是在 EDT 内

      您可以随时使用SwingUtilities.isEventDispatchThread() 查询您是否在 EDT 中

      另请注意,在您的代码中,当您已经在 EDT 中时,对 invokeAndWait 的调用将失败并引发错误

      【讨论】:

        【解决方案3】:

        诀窍是当 swing 呼叫你时,它总是在 EDT 中,所以你不必担心。

        但是,如果您处于计时器或由其他外部事件、主线程或您创建的任何其他线程触发的操作中,那么是的,您必须使用 invokeLater 或 invokeAndWait。

        换句话说,是的,swing 确实会自动执行“它”。需要使用invokeXx 的情况非常少见,如果swing 在内部使用它会浪费太多时间。

        许多 Java 程序员从来没有弄清楚这一点,它可能会在绘制 GUI 时导致一些非常讨厌的难以发现的问题。我希望 Swing 在您调用它而不使用 EDT 时抛出异常——如果这样做的话,Java 在专业 GUI 方面会有更好的声誉,因为那里的废话会更少。

        【讨论】:

        • 不如您希望的那样好,但您可以安装自动 Swing/EDT 违规检测代码,它们确实捕获了很多错误(手边没有任何链接,但其中有很多) )。
        • 微软在 windows 3.0/3.1 时代有“调试二进制文件”可以进行这种检查,这样你就不必每次发送错误参数时都重新启动。 Java 没有相同的功能总是困扰着我——尤其是因为它足够聪明,可以在命令行开关上编译出来。
        • 我过去总是将它“放入”Java 应用程序中,用 CheckThreadViolationRepaintManager 替换重绘管理器。我记得效果很好:)
        • 现在我现在想起来,用方面来解决它可能是一件容易的事情,但另一方面我不太担心我,我担心其他人会四处走动让人觉得没有什么好的java gui。另一个好的检查是确保 EDT 线程在您的代码中花费的时间永远不会超过 0.01 秒左右 - 任何时间都不会超过它应该抛出一个异常,告诉您将其放入工作线程中。
        【解决方案4】:

        基本上,您不会从 EDT 外部绘制或更新 GUI。 您使用来自另一个线程的 SwingUtilitis.invokeLater() 来确保在 EDT 上运行 GUI 绘图或更新代码。

        【讨论】:

        • 只是绘图代码?我可以摆脱诸如 setSize() 和 setVisible() 之类的杂乱无章的事情吗?
        • 通过绘制代码,它意味着对 GUI 组件的任何更新,所以是的,setSize() 和 setVisible() 是绘制代码的一部分。
        • 您还应该创建新线程来在 EDT 之外执行昂贵的任务,否则您可能会冻结 UI。
        猜你喜欢
        • 2011-01-29
        • 2015-11-06
        • 2011-11-11
        • 2011-02-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-25
        • 1970-01-01
        相关资源
        最近更新 更多