Java Swing – 在EDT上运行
关于Swing和使用EDT进行GUI更新,我有几个问题。 我刚刚开始阅读这些内容,所以我是这个领域的初学者:
- 在EDT上运行需要哪些操作? 如果他们不这样做,只是提出exception?
- 我们实际上在EDT上是否有任何特定的时间?
- 如果我们使用
SingUtilities.invokeLater
计划任务,我们将它排入GUI更新任务的当前队列吗? - 访问上面的队列我猜是同步的,或者使用了一些并发集合,但如果我从两个后台线程安排两个GUI更新任务,就不可能说先添加哪一个? 例如,如果线程1 FIRST提交了将JLable的文本设置为“是”的任务,然后,短时间后,第二个线程出现并提交将该值设置为“no”的任务,我们是否保证结果将是“是”,或者仅仅是操作系统如何安排这些事情的问题?
-
SwingWorker究竟如何确保在EDT上运行
done()
方法? 它设置以下代码:future = new FutureTask(callable) { @Override protected void done() { doneEDT(); setState(StateValue.DONE); } };
所以我想知道FutureTask是否确保调用invokeLater
?
谢谢你的所有答案。
- 一个好的规则是所有操作(访问/更新/ ……)都应该在EDT上进行。 javadoc中提到了一些例外(某些类的某些方法),但它们很难记住,更容易坚持“在EDT上做所有事情”的方法。 不会例外(幸运的是,JavaFX解决了这个缺点)。 您可以使用自定义
RepaintManager
来检测大多数这些违规:请参阅此文章 。 - 用户触发的所有内容都在EDT上处理。 例如,如果用户单击按钮,则将在EDT上调用相应
Action
或ActionListener
的actionPerformed
。 - 正确
- 您首先安排的事情将首先执行。
invokeLater
调用只是在队列末尾添加Runnable
。 稍后再使用invokeLater
将在先前调度的Runnable
之后添加此新的Runnable
。 -
看看
doneEDT
的代码private void doneEDT() { Runnable doDone = new Runnable() { public void run() { done(); } }; if (SwingUtilities.isEventDispatchThread()) { doDone.run(); } else { doSubmit.add(doDone); } }
- 基本上,每次使用Swing组件或Swing组件的模型时,都必须在EDT中完成。 如果不这样做,则不会引发任何例外。 它可以工作,但它也可能无法工作,行为不稳定,数据损坏等。
- 每个Swing事件监听器都在EDT中调用。 基本上,除了main方法之外,Swing应用程序的每一行代码都默认在EDT中执行,除非您明确地启动一个线程,使用SwingWorker或类似的东西。
- 是。
- 提交给SwingUtilities.invokeLater()的任务按照与提交顺序相同的顺序执行。
- 在内部,它使用SwingUtilities.invokeLater()或类似的方法。 FutureTask与Swing没有任何关系。 SwingWorker确保其完成方法在EDT中执行。
doneEDT()
方法具有以下注释: 在EDT上完成调用 。
SwingWorker通过以下代码确保在EDT上运行done()方法:
Runnable doDone = new Runnable() { public void run() { done(); } }; if (SwingUtilities.isEventDispatchThread()) { doDone.run(); } else { doSubmit.add(doDone); }
实际上它将doDone变量添加到AccumulativeRunnable doSubmit中,
查看AccumulativeRunnable.java的源代码,你会发现它有以下代码
protected void submit(){
SwingUtilities.invokeLater(本);
}
这就是为什么swingworker确保在EDT上运行方法done()的原因
1.在Java GUI应用程序中, main()
方法不长, 在 Event Dispatcher Thread
GUI的构造之后 , main()
方法退出……现在它的EDT负责处理GUI。
2.所以我们不需要在EDT上启动我们的应用程序, 它会自动完成。
3始终保持UI工作在UI线程上,非UI工作在非UI线程上。
因此,请始终保留您的EDT线程,这是仅用于GUI工作的GUI线程。
例如:
public static void main(String[] args){ EventQueue.invokeLater(new Runnable(){ public void run(){ myframe.setVisible(true); } } }
4.创建一个单独的非UI线程来处理该长时间的获取方法。
5.您可以简单地使用Thread
或使用专门引入Java的SwingWorker
来同步UI和非UI线程。
6. SwingWorker不确保在EDT上运行done()方法,而是将其输出同步到EDT线程,这是GUI线程。