2010-06-07 17 views
8

在引入Java內存模型之後,Swing準則已更改爲聲明任何Swing組件都需要在EDT上實例化,以避免未發佈的實例狀態。是否允許在非EDT線程中加載Swing類?

我無法在任何地方找到的是類加載是否也要求在EDT上,或者我們能否在後臺線程中預加載關鍵的Swing類? Sun/Oracle對此有任何官方聲明嗎?是否有已知的類可以保持非線程安全的靜態狀態,因此需要在EDT上加載?

澄清解決Nemi的問題:這是一個實際問題。我們的應用程序啓動時間的相當一部分,是在EDT上花費類加載和字體/圖像加載。其中大部分可歸因於Swing和相關的圖書館。

以下是som背景:與其他許多Swing應用程序一樣,我們在啓動時預構造了許多表單,以便使UI更加靈敏。分析後,我們發現表單構建的實際時間相對較快 - 緩慢的是所有類和字體的加載(磁盤讀取爲緩慢在公司設置與按訪問病毒掃描儀,監視掃描儀,審計跟蹤器和天知道還有什麼別的硬盤驅動器)。

我們試圖在後臺線程中構造相同的表單(違反了Swing的規則),然後將它們丟棄。一旦我們完成了,我們在EDT上構建相同的表單,因爲所有類都被加載並且其他任何文件都在磁盤緩存中,所以速度更快。它適用於我們,我們可能會繼續這樣做,除非發生非常糟糕的事情。

我在問的是這是安全的做法,一個好的做法還是一個黑客?

+0

特別是,兩個單班我能想到的是UIManager的和AppContext的。兩個javadocs都沒有說明它們是否應該是線程安全的。 除了isDisposed()方法沒有正確讀取狀態(需要同步)之外,AppContext的外觀正確同步。 UIManager對所有人都是免費的,但一旦EDT開始,我不認爲其他線程會改變它。 – ddimitrov 2010-06-07 01:34:05

+0

這是一個有趣的問題。這是純粹的學術,還是有一個真正的問題,你正在試圖解決?我想不出有什麼好的理由可以做到這一點。 – Nemi 2010-06-07 16:28:52

+0

@Nemi,給問題增加了更多的上下文 – ddimitrov 2010-06-07 23:09:53

回答

2

證據似乎表明它是安全的 - 但是再次如ddimitrov在評論中所述 - 由於未發佈的更改導致無法找到微妙的線程錯誤,因爲典型的機器只有少量內核,和L2/L3高速緩存是共享的。 (L1緩存是每個核心,但通常非常小)。

如果您希望保證沒有因後臺類加載而出現問題,那麼堅持在ETD上加載類可能是最安全的。爲了維護一個實時UI,創建一個自定義類加載器,該加載器還可以在加載每個類之間抽取事件。 (依賴性被重新加載,所以延遲只會在加載一個類的時間內)。假設這個類加載器與應用程序一起打包,那麼它可以簡單地將所有類加載推遲到它的類加載器。

或者,輔助事件隊列可以跨越獨立線程(例如模式對話框和spin庫)運行。這意味着Swing可以在任何線程上運行,只要它運行在一個線程上,並且意味着它必須是更新一致的(或者我們到目前爲止都非常幸運!)在此基礎上,您可以在主EDT上加載你的課程,並啓動輔助EDT來抽取UI事件,保持UI的響應 - 與模態對話框功能相同。 Spin實用程序將爲您提供EDT事件,或者您可以手動產生新的EDT。

+0

謝謝,這回答我的問題。 – ddimitrov 2010-06-09 23:33:15

+0

考慮到這一點,在老式的EDT上運行Swing是安全的,因爲Thread.start()是一個安全的出版物。然後爲了看到我們需要的變化或者線程。加入()臨時調度器或產生另一個調度器(這將看到新加載的類)並殺死舊的EDT。聽起來很混亂... – ddimitrov 2010-06-09 23:50:59

+0

如果您使用旋轉庫,細節將得到照顧。我不認爲這很像你所害怕的那麼混亂 - 次要的EDT可以通過發佈一個事件來終止。在加載所有類之後,執行此操作,並執行Thread.join()。 – mdma 2010-06-09 23:55:03

0

雖然你在技術上是正確的 - 但我從來沒有聽說過在不同的線程中渲染表單時出現問題,只要你沒有對它們做任何事情,原始指導方針)。

那些曾經是太陽的指引,但孫改變他們爲你所指定的 - 所以我敢肯定有人發現或創建了一個潛在的衝突,但我也確定它會很難打,因爲應用程序仍然有效,幾乎沒有遵循這些準則。

至於你的問題,我相信你可以加載類,只要你沒有實例化任何對象,並仍然在最嚴格的指導方針。

EDT僅用於避免線程衝突,因爲Swing是單線程的(按設計)。如果你只是加載類而不是實例化任何東西,那麼你並沒有打開任何線程問題。

+0

讓我擔心的是靜態。 EDT規則正在解決原子性問題,但並不關心可見性 - 在一個線程中將字段設置爲值並不能保證從另一個線程可見,除非正確發佈完成(例如通過同步,CAS等) 。請注意,現在,兩個線程將安排在同一個CPU上的機會很高。隨着多核系統的出現,這個問題將變得非常重要。 – ddimitrov 2010-06-08 04:13:44

+0

@ddimitrov事情是,直到意識到,其他任何線程纔有機會訪問它。現在,一定有一些機會,但只是加載類不會導致問題,因爲沒有代碼在類中運行。我不確定你不同意什麼(如果有的話)。當你真正實例化它並且永遠只能使用EDT時,這並不意味着EDT必須被用來加載類似OP的問題。 – 2010-06-08 15:17:35

+0

加載類時,任何靜態初始化器都在加載線程中運行,並且任何非最終靜態都受安全發佈規則的約束。我相信在Swing中沒有太多可變的靜態,但是(就像我舉的例子),有一些。否則,我同意問題發生的機率很低,但是如果出現問題,就不可能診斷甚至可靠地複製。 – ddimitrov 2010-06-08 23:50:05

2

這是安全的。請參閱:http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html(單線程規則)

如果您害怕或想要一些反饋/調試,請查看此FEST/Swing工具:http://fest.easytesting.org/swing/wiki/pmwiki.php?n=FEST-Swing.EDT(「測試訪問GUI組件是在EDT中完成的)」 - 這是自定義RepaintManager,當您違反EDT訪問策略時會失敗。

你會發現這是很有幫助的還有:http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html

他們沒有提到的類加載明確,但他們解釋EDT訪問策略是什麼。

+0

我不是在談論這裏的EDT政策違規問題。美國東部時間的政策不是一個專斷的規則,這是有原因的,我覺得它不完整。有關更多詳細信息,請參閱mdma的答案。 – ddimitrov 2010-06-09 23:32:29