我是Java的新手,在阅读了很多关于线程和swing的文章后,我明白所有Swing方法的调用都应该在EDT上完成,因为Swing不是线程安全的。但是,在阅读有关EDT之前,我已经编写了几个相当长的Swing应用程序。我的所有应用程序都运行得很好。所以我的问题是我的Swing应用程序默认运行在EDT上,还是在不同的线程上运行,我很幸运,没有任何问题?
例如,如果我将JButton添加到JPanel或JFrame,或者我只是调用JTextField的Field.setText()
,默认情况下这些操作是否会在EDT上运行?
如果答案是否定的,那么我是否必须通过调用SwingUtilities.invokeLater()
由于
答案 0 :(得分:6)
记住,对象不会存在于线程上,只会在线程上执行方法。
来自swing组件的所有动作(通过侦听器)自动在EDT上运行。
例如,您点击的按钮,onClicked()
功能已在EDT上运行,因此您无需执行任何操作。
如果你没有明确地创建任何线程,你的基本应用程序将有一个主线程和一个EDT(以及许多其他线程,你不会意外地执行你的代码,直到你开始使用额外的框架)。
您必须手动完成的事情是在EDT上构建GUI。正如您所见here,这可以在主线程中完成,如下所示:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
MyWindow window = new MyWindow ();
window.setVisible(true);
}
});
如果您未能正确使用EDT。一切似乎都能正常工作,但偶尔你会得到非常奇怪的行为(因为两个线程会做的事情而不是一个)。
总而言之,在以下情况下,您必须使用invokeLater()
或某些例外invokeNow()
:
这个question包含一些可以帮助您自动检测错误的工具(尽管不是全部)。
答案 1 :(得分:4)
默认情况下我的Swing应用程序在EDT上运行,或者他们是在不同的线程上运行的,我很幸运,没有任何问题吗?
他们大多是在EDT上跑。 Swing所做的所有绘画和更新都在EDT上。你在代码库中专门做的事情,你知道在EDT上没有,是EDT上没有的代码。所以这些操作就像查询JLabel的文本,设置JLabel的文本或初始化JLabel本身一样。
然后,您在代码库中实现的Swing执行的各种侦听器方法在EDT上执行(只要Swing调用它,而不是您自己)。因此,在这些方法中,您可以查询/修改Swing组件,但请记住正确地传入和传出您提供给Swing组件的任何数据,或者以线程安全的方式从Swing组件查询。
例如,如果我创建一个JButton并将其添加到JPanel或JFrame,默认情况下这些操作是在EDT上运行还是没有?
对象的初始化发生在你创建它们的任何线程上,Swing对象的其余修改也是如此(比如将一个组件添加到另一个组件)。我不知道任何Swing组件的公共方法实现都包含在它们自己的invokeNow()或invokeLater()调用中,因此最好假设所有操作部分都发生在你调用原始方法的任何线程上
我是否必须通过调用SWUNUtilities.invokeLater()
显式发送我在EDT上运行的所有Swing组件和方法
是,或者invokeNow()
答案 2 :(得分:1)
将在调用它们的线程上下文中访问组件,这会导致问题......
所有Swing组件(或者根本不重要)MIST可以在事件调度线程的上下文中被访问,一旦它们被添加到可显示的容器(连接到本地对等体)。
这使得Swing组件不是线程安全的,你有责任确保从EDT正确地修改/访问它们,框架不会为你做这个
请查看Concurrency in Swing了解详情