【问题标题】:invokeAndWait method in SwingUtilitiesSwingUtilities 中的 invokeAndWait 方法
【发布时间】:2011-07-26 21:00:05
【问题描述】:

请解释 SwingUtilities 中的 invokeAndWait() 方法。我无法理解这一点。 解释的很清楚。 如果你用一个例子来尝试会很有帮助。

已编辑添加@noob 对问题的扩展:

this 有什么不清楚的地方?

这是一个修改后的用法示例:

import javax.swing.SwingUtilities;

public class InvokeAndWaitStuff 
{
    public static void main(String[] args)
    {
        final Runnable doHelloWorld = new Runnable() {
             public void run() {
                 System.out.println("Hello World on " + Thread.currentThread());
             }
         };

         Thread appThread = new Thread() {
             public void run() {
                 try {
                     SwingUtilities.invokeAndWait(doHelloWorld);
                 }
                 catch (Exception e) {
                     e.printStackTrace();
                 }
                 System.out.println("Finished on " + Thread.currentThread());
             }
         };
         appThread.start();
    }
}

输出:

Hello World on Thread[AWT-EventQueue-0,6,main]
Finished on Thread[Thread-0,5,main]

为什么这很重要?:

导致 doHelloWorld.run() 成为 在 AWT 上同步执行 事件调度线程。这个电话 阻塞直到所有未决的 AWT 事件 已被处理并且(然后) doHelloWorld.run() 返回。这 当一个方法应该使用 应用程序线程需要更新 图形用户界面。

据我所知,这基本上是一个瓶颈,迫使 GUI 更新由单个线程同步执行,而不是由多个线程异步执行,这可能是不安全的。

【问题讨论】:

  • 您阅读过文档吗?
  • 向我们展示一些导致您缺乏理解的损坏代码,我们将向您展示有助于解决问题的固定代码。

标签: java swing


【解决方案1】:

要了解invokeAndWait()的作用,首先需要了解Swing的事件/线程模型。

基本上,以任何方式影响 GUI 的所有事情都必须发生在单个线程上。这是因为经验表明多线程 GUI 是不可能正确的。

在 Swing 中,这个特殊的 GUI 线程称为事件调度线程,或 EDT。它在显示 Swing 顶级组件时立即启动,并且它基本上是一个工作线程,具有一个接一个地执行的事件对象的 FIFO 队列。

当需要绘制或更新 Swing GUI 时,JRE 会在 EDT 队列中放置一个事件。导致调用侦听器的用户操作作为 EDT 队列上的事件开始。并且(这是重要的部分)您的程序所做的所有更改 GUI(如注册侦听器、添加/删除 GUI 组件或更改 GUI 显示的模型数据)都必须放在 EDT 队列中,否则 GUI 可以获得损坏。

现在完成:invokeAndWait() 将您传递给它的 Runnable 放入 EDT 事件队列并等待直到 EDT 执行它。 这应该在非GUI 线程需要做一些影响 GUI 的事情,但也需要等到它真正完成后才能继续。如果您只想做一些影响 GUI 但不关心何时完成的事情,您应该改用invokeLater()

【讨论】:

  • @Michael:对于除 EDT 之外的线程,是否有类似于 invokeAndWait 的内容?我发现这将非常有用,尤其是如果您希望顺序执行多个任务...
  • @noob:来自 java.util.concurrent 的 Executors.newSingleThreadExecutor() 生成一个 ExecutorService,它基本上就像 EDT 一样工作。然后,您可以 submit() Runnables 并在返回的 Future 上调用 get() 以等待其完成。
  • @Michael:谢谢!而且我想我的答案是错误的,或者是因为它被删除了。太棒了!
  • @noob:例如,看看这里,它可能会给你一些想法。 stackoverflow.com/questions/1322147/…
  • 值得注意的是,在EDT中不要调用invokeandwait,否则程序会死锁...
【解决方案2】:

我在 JTable 中遇到了类似的问题。该程序在“scrollRectToVisible”方法中的某处被阻止。我已经通过将调用包装在 invokeLater 调用中来替换调用。 invokeAndWait 没有解决我的阻塞问题。

    SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
            table.scrollRectToVisible(r);
        }

    });

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-02
    • 2012-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-16
    • 1970-01-01
    相关资源
    最近更新 更多