Re:要求在Event-Dispatch Thread上创建Swing对象。
我正在开发一个应用程序,其目的是监视和显示各种远程嵌入式服务器的状况。我对Java很陌生,而且我对Swing对象和EDT的要求的理解还不完整。
主GUI以常规方式在EDT上启动,如下所示,
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
然后,用户可以选择与一个或另一个远程机器相对应的一个或多个菜单选项。这样做的效果是每次都创建一个新线程,如下所示
new Thread(new VoterStatus(itemNumber)).start();
调用VoterStatus的类“run”方法,该方法又创建一个带有JFrame的新窗口。新线程(VoterStatus类的一个实例)然后询问(TCP等)指定的特定远程(itemNumber),收集各种信息并在JFrame中显示它们。
可能有任意数量的此类线程对应于VoterStatus的实例,所有这些都更新了自己的窗口。这些不同的窗口/ JFrame /任务之间没有数据共享。
这似乎工作得很好,但是安全吗?
我是否违反了有关在EDT上创建Swing组件的规则?
使用SwingWorker类会有益吗?
我很感激Java程序员在这些问题上更有经验的评论。
由于 史蒂夫
答案 0 :(得分:5)
来自标题为The Event Dispatch Thread
的Swing教程中的部分一些Swing组件方法在API规范中标记为“线程安全”;这些可以从任何线程安全地调用。必须从事件派发线程调用所有其他Swing组件方法。忽略此规则的程序可能在大多数情况下正常运行,但会遇到难以重现的不可预测的错误。
我总是在EDT上调用我的方法,所以我不会浪费时间追逐小鬼。
编辑:
我刚刚阅读了另一篇帖子,其中指出JDK7 API中的许多方法都删除了“线程安全”注释。 http://forums.oracle.com/forums/thread.jspa?threadID=2167051。这看起来是确保影响GUI的所有方法都在EDT上执行的另一个原因。
答案 1 :(得分:2)
@camickr有权利。错误同步的程序可能出现以便大多数工作,但结果不可靠。讨论了几种相关方法here。 SwingWorker
是Future
接口的一个特别方便的实现,因为process()
在事件派发线程上运行。
答案 2 :(得分:0)
您可能是安全的,但您可以通过在EDT中创建其他UI组件来确定,就像您对主应用程序所做的那样。
但是,我建议采用不同的方法。不是为每个新Thread
触发创建窗口和内容的新VoterStatus
,而是在EDT中创建UI组件以响应菜单中的ActionEvents
或其他任何内容,并进行处理网络的东西只在不同的线程中。然后得到结果并使用EDT显示它们。正如您所建议的那样,SwingWorker
对此非常理想 - 这正是它的设计用途。这对我来说代表了一种更清晰的分离,尽可能地将UI内容与网络内容分开。
答案 3 :(得分:0)
我并没有真正回答我自己的问题,但我确实要感谢那些回复并提出一两个问题的跟进问题。
Rogash评论说,如果我只是在EDT上创建GUI,我会没事的,但这似乎与规则的严格解释不一致?
其他线程在EDT中创建,但它们仍然是单独的线程。
虽然可能需要稍微更好地分离GUI和通信,但我希望这会给主GUI代码增加相当大的复杂性,因为它必须确定哪个窗口发起了各种事件然后更新了正确的窗口,更不用说了各种线程和主GUI线程之间的通信。也许我夸大了这个难度(我还没有设计或想过如何编码它)但它似乎更复杂。每个线程/ JFrame已经有一些JToggleButton数组(30个元素)导致潜在事件和10个左右的JTextField数组具有相同数量的需要更新的元素。
当然,如果我的方法不安全,我将不得不改变它,就是这样!
实际上,我想知道我是否可以更好地保留原样,并使用互斥锁或信号量来确保一次只有一个线程访问Swing方法。实际上没有长时间的用户操作或任何其他活动需要很长时间,只需要接收大量的TCP或UDP数据包,需要更新屏幕显示。
再次感谢 史蒂夫
PS我试图在这个论坛上注册,但我认为这个讨论会留在我未注册的人物中。