如果在Swing中打开一个对话框,例如JFileChooser,它的伪代码如下:
Swing事件线程 { 创建对话框 添加对话框关闭事件监听器 { returnValue = somethingFromDialog } 显示对话框 (等待直到关闭) 返回returnValue }
我的问题是:这怎么可能行得通?正如您所看到的,该线程在等待对话框关闭之前将被阻塞。这意味着Swing事件线程被阻塞。但是,人们可以与对话框交互,这据我所知需要运行此线程。
那么这是如何工作的?
如果在Swing中打开一个对话框,例如JFileChooser,它的伪代码如下:
Swing事件线程 { 创建对话框 添加对话框关闭事件监听器 { returnValue = somethingFromDialog } 显示对话框 (等待直到关闭) 返回returnValue }
我的问题是:这怎么可能行得通?正如您所看到的,该线程在等待对话框关闭之前将被阻塞。这意味着Swing事件线程被阻塞。但是,人们可以与对话框交互,这据我所知需要运行此线程。
那么这是如何工作的?
"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");
}
});
然后断点,查看线程,您将只看到一个EventQueue线程。JOptionPane的show()方法本身会推动事件。
像Spin和Foxtrot这样的框架采用相同的方法 - 它们允许您在EDT上创建长时间运行的阻塞方法,但通过自己推动事件来保持事件流动。虽然Swing可以有多个分派线程(我确信早期版本的Swing是这种情况),但现在多核已经很常见,因此并发问题,特别是确保在一个线程上的更改正确发布到其他线程,意味着在当前实现中使用多个EDT会产生错误。请参见Multiple Swing event-dispatch threads
这是AWT线程,而不是Swing的。
无论如何,AWT在show
中运行调度循环。对于被阻止的窗口的输入事件会被阻塞。重绘事件、未被阻塞的窗口的事件和一般事件将像往常一样被分派。
您可以通过添加以下行来查看:
Thread.dumpStack();
jstack
或在应用程序的命令窗口中使用ctrl-\
/ctrl-break
,可以将模态对话框转换为事件处理,或更容易地进行转换。 Foxtrot库滥用了这一点,以提供更加过程化的(而不是事件驱动的)模型。当从应用程序EDT调用时,WebStart/Java PlugIn也会使用它来为JNLP服务和其他服务提供对话框。