Swing 对话如何工作?

如果你在 Swing 中打开一个对话框,例如一个 JFileChooser,它有点像这个伪代码:

swing event thread {
  create dialog
  add listener to dialog close event {
    returnValue = somethingFromDialog
  }
  show dialog
  (wait until it is closed)
  return returnValue
}

我的问题是:这怎么可能起作用?如您所见,线程一直等待返回,直到对话框关闭。这意味着 Swing 事件线程被阻止。但是,可以与对话框进行交互,AFAIK需要此线程才能运行该对话框。

那么这是如何运作的呢?


答案 1

现有的事件调度线程被阻塞,因此 swing 会创建另一个抽取事件的线程。然后,这是对话期间的事件调度线程。

Swing 创建一个单独的本机线程,用于抽取本机操作系统窗口消息。这与 AWT 事件线程是分开的。

在 Windows 上,您会看到这些线程

  "AWT-Windows"   - the native UI thread
  "AWT-EventQueue-0" - the current AWT event dispatch thread

编辑:投反对票是正确的。事实并非如此,至少并非在所有情况下都是如此。

模式对话框通常负责泵送 AWT 事件本身。如果运行代码

SwingUtilities.invokeAndWait(new Runnable()
{
    public void run()
    {
        JOptionPane.showInputDialog("hello");
    }
});

然后中断,查看线程,您将只看到一个事件队列线程。JOptionPane 的 show() 方法泵送事件本身。

Spin和Foxtrot这样的框架采用相同的方法 - 它们允许您在EDT上创建长时间运行的阻塞方法,但通过泵送事件本身来保持事件的流动。Swing可以有多个调度线程(我确信旧版本的swing就是这种情况),但是现在多核很常见,并发问题,特别是确保一个线程上的更改正确发布到其他线程,意味着使用多个EDT会在当前实现中产生错误。请参阅多个 Swing 事件调度线程


答案 2

这是AWT的线程,而不是Swing的线程。

无论如何,AWT 在 运行调度循环。阻止被阻止窗口的输入事件。重新绘制事件、将事件重新绘制到未阻止的窗口和常规事件,将照常调度。show

您可以通过添加以下行来查看此内容:

 Thread.dumpStack();

进入均匀处理模式对话框,或更容易从命令行使用或使用/在应用程序的命令窗口中。jstackctrl-\ctrl-break

Foxtrot库滥用它来提供一个更加程序化(而不是事件驱动)的模型。WebStart/Java PlugIn也使用它来为JNLP服务和其他服务提供对话框,当从应用程序EDT调用时。