回答
從不做長時間運行的任務來響應按鈕,事件等,因爲它們在事件線程中。如果阻塞事件線程,則整個GUI將完全無響應,從而導致非常生氣的用戶。這就是爲什麼Swing看起來很慢而且很硬。
使用線程,執行程序和SwingWorker來運行不在EDT(事件調度線程)上的任務。
請勿在EDT之外更新或創建窗口小部件。在美國東部以外地區唯一可以做的就是Component.repaint()。使用SwingUtilitis.invokeLater確保在EDT上執行某些代碼。
使用EDT Debug Techniques和一個聰明的外觀和感覺(如Substance,其檢查EDT違規)
如果你遵循這些規則,鞦韆可以做一些非常有吸引力的,反應的GUI
的一些非常棒的Swing UI工作示例:。注意:我不爲他們工作,只是一個令人敬畏的揮杆的例子。恥辱沒有公開演示...他們的blog也不錯,稀疏但很好
除了事件派發線程之外,主動避免執行任何Swing工作。 Swing寫得很容易擴展,Sun決定使用單線程模型更好。
我沒有問題,同時遵循我的建議。在某些情況下,你可以從其他線程「擺動」,但我從來沒有找到需要。
這不僅僅是Swing不是線程安全的(不是很多),但它是線程敵對的。如果你開始在單線程(EDT之外)上執行Swing東西,那麼當Swing切換到EDT(未記錄)時,可能會出現線程安全問題。即使Swing文本的目標是線程安全的,也不是線程安全的(例如,追加到文檔中,您首先需要查找長度,在插入之前可能會更改該長度)。
因此,在EDT上執行所有Swing操作。注意EDT不是線程的主叫,所以啓動(簡單)Swing應用程序這樣的樣板:
class MyApp {
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() { public void run() {
runEDT();
}});
}
private static void runEDT() {
assert java.awt.EventQueue.isDispatchThread();
...
如果您使用的是Java 6的SwingWorker那麼肯定是要對付這種最簡單的方法。
基本上你想確保在EventDispatchThread上執行任何改變UI的東西。
這可以通過使用SwingUtilities.isEventDispatchThread()方法來告訴你,如果你在它(通常不是一個好主意 - 你應該知道什麼線程是活動的)。
如果您不在EDT上,那麼您可以使用SwingUtilities.invokeLater()和SwingUtilities.invokeAndWait()來調用EDT上的Runnable。
如果你更新UI上的不在EDT上,你會得到一些令人難以置信的奇怪行爲。就我個人而言,我不認爲這是Swing的缺陷,你不需要同步所有線程來提供UI更新,就可以獲得一些很好的效率 - 你只需要記住那個警告。
這是讓我很高興的其中一個問題,我購買了Robinson & Vorobiev's book on Swing。
凡是訪問java.awt.Component
的狀態應該在美國東部時間內運行,有三個例外:任何具體的記錄爲線程安全的,如repaint()
,revalidate()
和invalidate()
; UI中的任何組件尚未被實現;以及Applet的start()
之前的Applet中的任何組件。
專門製作線程安全的方法非常罕見,通常只需記住那些方法就足夠了;您通常也可以假設沒有這樣的方法(例如,將重繪調用包裝在SwingWorker中是完全安全的)。
實現意味着該組件可以是一個頂層容器(像的JFrame),其上的setVisible(true)
,show()
,或任何pack()
已被調用,或者它已被添加到一個實現組件。這意味着在main()方法中構建用戶界面非常好,正如很多教程示例所做的那樣,因爲在頂級容器上不會調用setVisible(true)
,直到每個組件都已添加到它,配置了字體和邊框等等
由於類似的原因,在init()
方法中構建小應用程序用戶界面非常安全,並且在構建完所有方法後再調用start()
。
包裝隨後的組件更改發送到invokeLater()
的Runnables變得很容易,只需幾次即可完成。我發現惱人的一件事是從另一個線程讀取組件的狀態(例如,someTextField.getText()
)。從技術上講,這也必須包含在invokeLater()
中;在實踐中,它可以使代碼變得很難,而且我經常不打擾,或者我在第一次事件處理的時候(通常是在大多數情況下通常是正確的時候這樣做)抓緊這些信息。
這是一個模式,可以讓線程自由擺動。
子類動作(MyAction)並使其成爲doAction線程。 使構造函數採用字符串名稱。
給它一個抽象actionImpl()方法。
讓它看起來像.. (僞警告!)
doAction(){
new Thread(){
public void run(){
//kick off thread to do actionImpl().
actionImpl();
MyAction.this.interrupt();
}.start(); // use a worker pool if you care about garbage.
try {
sleep(300);
Go to a busy cursor
sleep(600);
Show a busy dialog(Name) // name comes in handy here
} catch(interrupted exception){
show normal cursor
}
可以錄製下一次拍攝任務的時間,而且,你的對話框可以顯示一個體面的估計。
如果你想真的很好,也可以在另一個工作線程中睡覺。
短語'線程不安全'聽起來像是有些天生不好的東西(你知道......'安全' - 好;'不安全' - 壞)。現實情況是,線程安全的代價是 - 線程安全的對象通常實現起來更加複雜(並且Swing足夠複雜,即使是這樣)。
此外,線程安全性可以使用鎖定(緩慢)或比較和交換(複雜)策略。鑑於GUI與人類交互,這往往是不可預知的並且難以同步,許多工具包已決定通過單個事件泵來引導所有事件。這對於Windows,Swing,SWT,GTK以及其他人來說都是如此。實際上,我不知道一個真正的線程安全的GUI工具包(這意味着你可以從任何線程操縱其對象的內部狀態)。
通常做的是,GUI提供了一種處理線程不安全的方法。正如其他人所指出的那樣,Swing總是提供了一些簡單的SwingUtilities.invokeLater()。 Java 6包含優秀的SwingWorker(可用於Swinglabs.org的以前版本)。還有Foxtrot等第三方庫管理Swing上下文中的線程。
Swing的惡名是因爲設計師採取了輕率的方法,假設開發人員會做正確的事情,而不是停止EDT或修改EDT以外的組件。他們已經明確表示了他們的線程策略,並且要由開發人員來遵循。
讓每個揮杆API向EDT發佈每個屬性集合,無效等等,這將使其線程安全,但代價是大幅度減速,這是微不足道的。你甚至可以使用AOP自己做。爲了比較,SWT在從一個錯誤的線程訪問一個組件時拋出異常。
請注意,即使模型接口都不是線程安全的。大小和內容使用單獨的get方法查詢,因此無法同步這些方法。
從另一個線程更新模型的狀態允許它至少繪製尺寸仍然較大(錶行仍在原地)的情況,但內容不再存在。
始終在EDT中更新模型的狀態可避免這些情況。
當您與任何非EDT EDT線程的GUI組件進行任何交互時,都必須使用invokeLater()和invokeAndWait()。
它可能在開發過程中工作,但像大多數併發錯誤一樣,您會看到奇怪的異常出現,看起來完全不相關,並且非確定性地發生 - 通常在真實用戶發貨後發現。不好。另外,你還沒有信心,你的應用程序將繼續在越來越多的內核的未來CPU上工作 - 由於它們是真正的併發而不是僅僅由操作系統模擬的,所以更容易遇到奇怪的線程問題。
是的,它變得醜陋,每一個方法回調到一個Runnable實例的EDT中,但這對你來說是Java。在我們關閉之前,你只能忍受它。
有關線程化的更多詳細信息,Allen Holub編寫的「馴服Java線程」是一本舊書,但是是一本很棒的閱讀。
Holub,確實可以促進響應式用戶界面和詳細示例以及如何緩解問題。
http://www.amazon.com/Taming-Java-Threads-Allen-Holub/dp/1893115100 http://www.holub.com/software/taming.java.threads.html
愛 「如果我是王」 到底有節。
使用智能皮膚類物質的替代方法是創建下面的實用方法:
public final static void checkOnEventDispatchThread() {
if (!SwingUtilities.isEventDispatchThread()) {
throw new RuntimeException("This method can only be run on the EDT");
}
}
調用它的每一個方法你寫的要求是事件調度線程上。這樣做的一個優點是可以快速禁用和啓用全系統檢查,例如可能會在生產中將其刪除。
注意智能皮膚當然可以提供額外的覆蓋範圍以及這一點。
- 1. 使用線程安全庫
- 2. PHP線程安全和非線程安全的Windows
- 3. SharedPreferences和線程安全
- 4. UIKit和GCD線程安全
- 5. Django和線程安全
- 6. Azure WebJobs和線程安全
- 7. 線程安全和AfxMessageBox
- 8. 塊和ViewController線程安全
- 9. urllib2和cookielib線程安全
- 10. 線程安全和MEF CompositionContainer
- 11. Scintilla和線程安全
- 12. Winsock和線程安全
- 13. python WSME和線程安全
- 14. 線程安全和`const`
- 15. C++線程安全和notify_all()
- 16. DefaultTraceListener和線程安全
- 17. SharePoint和線程安全
- 18. 線程安全
- 19. 線程安全
- 20. 線程安全
- 21. 線程安全
- 22. 線程安全
- 23. 線程安全
- 24. 線程安全
- 25. 共享庫(dlopen)和庫靜態指針的線程安全性
- 26. 會話線程安全嗎?SMPP Logica庫
- 27. Java線程安全數據庫連接
- 28. 製作C庫線程安全
- 29. msgsnd()線程和/或進程安全嗎?
- 30. 線程安全應用程序中的線程安全
還有一個invokeAndWait()方法,但儘可能使用invokeLater()。 – Powerlord 2008-10-08 12:16:55
如果您想要死鎖,請使用invokeAndWait。 ;) – 2008-10-08 13:03:18
或按小時支付。 :-) – 2008-10-08 15:14:55