简体   繁体   English

是否可以在非EDT线程中加载Swing类?

[英]Is it allowed to load Swing classes in non-EDT thread?

After the introduction of Java Memory Model, the Swing guidelines were changed to state that any Swing components need to be instantiated on the EDT in order to avoid non-published instance state. 引入Java内存模型后,Swing指南进行了更改,以声明需要在EDT上实例化任何Swing组件,以避免出现未发布的实例状态。

What I could not find anywhere is whether the classloading is also mandated to be on the EDT or can we pre-load key Swing classes in a background thread? 我在任何地方都找不到的是类加载是否也必须在EDT上进行,还是我们可以在后台线程中预加载关键的Swing类? Is there any official statement from Sun/Oracle on this? Sun / Oracle是否对此发表任何官方声明? Are there any classes that are known to hold non-threadsafe static state, hence need to be loaded on EDT? 是否有任何已知持有非线程安全静态状态的类,因此需要在EDT上加载?

Clarification to address Nemi's question: this is a practical issue. 澄清以解决内米的问题:这是一个实际问题。 A sizable portion of our application's startup time, is spent classloading, and font/image-loading on the EDT. 在应用程序启动时间中,相当大一部分用于在EDT上进行类加载和字体/图像加载。 Most of this can be attributed to Swing and related libraries. 其中大部分可以归因于Swing和相关库。

Here is som background: As many other Swing apps, on startup we are pre-constructing many forms, in order to make the UI more responsive. 这是Som背景:与其他许多Swing应用程序一样,在启动时我们正在预先构造许多表单,以使UI响应更快。 After profiling, we found that the actual time for form construction is relatively fast - what's slow is loading of all classes and fonts (disk reads are slow in corporate setup with on-access virus scanner, surveilance scanner, audit tracker and god knows what else tacked on the HDD driver). 经过分析后,我们发现表单构建的实际时间相对较快-加载所有类和字体的速度慢(在使用按需访问病毒扫描程序,监视扫描程序,审核跟踪程序的公司设置中,磁盘读取速度 ,而上帝知道其他什么附加到HDD驱动程序上)。

We tried to construct the same forms in a background thread (violating Swing's rules) and then throw them away. 我们试图在后台线程中构造相同的表单(违反了Swing的规则),然后将其丢弃。 Once we are done we construct the same forms on the EDT, which is much faster as all classes are loaded and any other files are in the disk cache. 完成后,我们将在EDT上构建相同的表单,这将更快,因为所有类都已加载,而其他文件都在磁盘缓存中。 It works for us, and we'll probably keep doing it unless something really bad happens. 它对我们有用,除非有真正不好的事情发生,否则我们可能会继续这样做。

What I'm asking is whether this is a safe practice, a good practice or a hack? 我要问的是这是安全的做法,良好的做法还是黑客?

It is safe. 很安全 See: http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html (the single thread rule) 请参阅: http : //java.sun.com/products/jfc/tsc/articles/threads/threads1.html (单线程规则)

If you are afraid or want some feedback / debug, have a look at this FEST/Swing tool: http://fest.easytesting.org/swing/wiki/pmwiki.php?n=FEST-Swing.EDT ("Testing that access to GUI components is done in the EDT") -- it is a custom RepaintManager that fails when you violate the EDT access policy. 如果您害怕或需要一些反馈/调试,请查看此FEST / Swing工具: http ://fest.easytesting.org/swing/wiki/pmwiki.php?n=FEST- Swing.EDT (“对GUI组件的访问是在EDT中完成的”)-这是一个自定义的RepaintManager ,当您违反EDT访问策略时会失败。

You may find this helpful as well: http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html 您可能也会发现这也很有帮助: http : //weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html

They don't mention class loading explicitly, but they do explain what the EDT access policy is about. 他们没有明确提及类加载,但是确实解释了EDT访问策略的含义。

The evidence seems to suggest it is safe - but then again, as ddimitrov says in the comments - the odds are in favor of not finding subtle thread bugs due to non-published changes because typical machines have only a few cores, and L2/L3 caches are shared. 证据似乎表明它是安全的-但是,正如ddimitrov在评论中所说,再说一遍,由于典型的机器只有几个内核,并且L2 / L3,所以由于未发布的更改而不太可能发现微妙的线程错误的可能性很大。缓存是共享的。 (L1 caches are per core, but usally very small.) (L1缓存是每个内核的,但是通常很小。)

If you want to guarantee no problem arises because of the background classloading, then it's probably safest to stick to loading classes on the ETD. 如果您想保证不会因后台类加载而出现任何问题,那么坚持在ETD上加载类可能是最安全的。 To maintain a live UI, create a custom class loader that also pumps events in-between loading each class. 要维护实时UI,请创建一个自定义的类加载器,该类加载器还会在加载每个类之间进行抽签。 (Dependencies are loaded re-entrantly so the delay would only be for the duration of loading just one class.) Assuming this class loader is packaged with your application, then it can simply defer all class loading to it's classloader. (依赖项是可重入的,因此延迟只会在仅加载一个类的持续时间内发生。)假定此类加载器与您的应用程序打包在一起,则可以将所有类加载推迟到其类加载器中。

Alternatively, Secondary event queues can be spanwed that run on separate threads (eg modal dialogs, and the spin library). 或者,可以扩展在单独线程(例如模式对话框和自旋库)上运行的次要事件队列。 This implies Swing can run on any thread, as long as it runs on just one, and means that it must be update-consistent (or that we've all just been very lucky so far!) On the basis of this, you could load your classes on the primary EDT, and start a secondary EDT to pump the UI events, keeping the UI responsive - in the same way a modal dialog functions. 这意味着Swing可以在任何线程上运行,只要它只能在一个线程上运行,这意味着它必须是更新一致的(或者到目前为止,我们所有人都很幸运!)在此基础上,您可以在主要EDT上加载类,然后启动次要EDT来泵送UI事件,使UI保持响应状态-就像模式对话框一样。 The Spin utility will pump EDT events for you, or you can spawn a new EDT by hand. Spin实用程序将为您泵送EDT事件,或者您可以手动生成新的EDT。

Although you are technically correct--I've never heard of a problem with rendering the forms in a different thread as long as you don't do anything with them once they are realized except with the EDT (as per sun's original guidelines). 尽管您在技术上是正确的-我从来没有听说过在不同的线程中呈现表单的问题,只要您意识到除了EDT之外就不对它们执行任何操作(根据sun的原始准则)。

Those used to be sun's guidelines but Sun changed them to be as you specified--so I'm sure someone found or created a potential conflict, but I'm also sure it's going to be damn hard to hit since apps still work and almost none follow those guidelines. 这些曾经是sun的准则,但是Sun更改了它们,使其符合您的指定-因此,我确定有人发现或造成了潜在的冲突,但是我也肯定,由于应用仍然可以正常工作且几乎可以没有人遵循这些准则。

As to your question, I'm sure you can load the classes as long as you don't instantiate any objects and still be within even the strictest guidelines. 关于您的问题,只要您不实例化任何对象并且即使在最严格的指导原则之内,我相信您都可以加载这些类。

The EDT is only used to avoid thread collisions because Swing is single threaded (by design). EDT仅用于避免线程冲突,因为Swing是单线程的(通过设计)。 If you are only loading the classes and not instantiating any, you aren't opening yourself up for any threading issues. 如果仅加载类而不实例化任何类,则不会为任何线程问题敞开大门。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM