在Java 7+中,在EDT之外使用Swing repaint()方法是否仍然安全?

时间:2014-01-03 14:35:30

标签: java multithreading swing repaint event-dispatch-thread

我知道,即使使用Swing的线程模型,也可以从任何线程调用repaint()和其他一些选定的方法被认为是安全的,但最近我在评论中告诉我不是这样。

谷歌发现很多旧的讨论说这是安全的,但最近没什么。所有过去曾经说过安全的官方参考资料似乎已经消失了,我在各个论坛上发现了一些人讨论它是如何不再安全的。

我找不到任何正式的信息来确认它是否存在 - 而且我真的希望看到一些解释改变逻辑的东西,如果它已被改变的话。考虑到破坏现有应用程序的风险有多严重,删除它似乎是一个非常奇怪的功能。

我真的在寻找一个官方参考链接(即Javadoc,oracle教程或源代码链接),说明这些方法是否可以安全地从任何线程调用。

此处提及此问题:

Safe to use Component.repaint() outside EDT?

从现已消失的Sun页面中引用一句话:

  

以下JComponent方法可以安全地从任何线程调用:repaint(),revalidate()和invalidate()。 repaint()和revalidate()方法将事件派发线程的请求分别调用paint()和validate()。

这符合我的理解,但我现在找不到那个页面或任何类似的页面,我看到几个人的未经证实的谣言说它不再安全。但另一方面,我找不到任何明确的说这个功能已经改变。

更改备注

可能有助于解决这个问题的是Oracle发布的关于Swing线程处理变化的官方声明。我找到了“Java 7中的更改”页面,但根本没有提到它,这些页面都没有提到任何方式的线程或EDT:

http://docs.oracle.com/javase/7/docs/technotes/guides/swing/enhancements-7.html

http://docs.oracle.com/javase/7/docs/technotes/guides/awt/enhancements-7.html

3 个答案:

答案 0 :(得分:8)

这是official reference

  

Swing的线程策略

     

一般来说,Swing不是线程安全的。除非另有说明,否则必须在事件派发线程上访问所有Swing组件和相关类。

repaint方法并非“以其他方式记录”。

再次向您保证,您不需要查看单个方法的Javadoc以获得明确答案,例如,请参阅Java 6 Javadoc中如何记录方法的线程安全性。

更新

显然,需要对规范性规范,描述性技术文章和任何具体实施细节之间的区别进行更多澄清。 Javadoc所说的是:无法保证repaint是一种线程安全的方法。顺便提一下,Java 7中经常讨论的从大多数Swing API中删除“线程安全”标识的决定只是:契约的更改,而不是实现。

OpenJDK 7中repaint的具体实现似乎是线程安全的,这与规范给出的保证无关。依赖于repaint或其他方法的线程安全性的代码已损坏,并且无法保证在所有Java实现上都能正常运行。

答案 1 :(得分:3)

正如Painting in AWT and Swing: Paint Processing中讨论的那样,

  

JComponent.repaint()向组件的RepaintManager注册一个异步重绘请求,该请求使用invokeLater()Runnable进行排队,以便稍后在事件调度线程上处理请求。

这是在repaint()的连续调用之间建立happens-before关系的必要条件,但不是充分条件。实际上,您仍然需要同步访问线程之间共享的任何数据。如果没有这个,就无法确保任何可能影响后续repaint()调用的更改的可见性。

答案 2 :(得分:2)

我会说它仍然是线程安全的。 repaint()方法不会更改任何Swing组件的属性。

repaint()方法调用RepaintManager。然后,RepaintManager将(可能)将多个绘制请求组合到一个绘制请求中。然后它会将油漆请求添加到EDT进行处理。