2011-08-27 40 views
48

我最近開始學習和探索Java中GUI編程的基礎知識。Java事件派發線程說明

已經編程了,而我也只是做後臺工作,或工作,因此我已經得到了用戶界面的最接近的是命令控制檯(尷尬的,我知道)。

我正在使用Swing,並且據我所知可以通過擴展來收集,我也使用AWT。

我的問題是在此基礎上一段代碼:

java.awt.EventQueue.invokeLater(new Runnable() { 
    public void run() { 
     new frame.setVisible(true); 
    } 
}); 

我一直在研究這一段時間,因爲我想完全理解這種奇怪的代碼和所遇到的術語「事件調度線程'多次。如果我錯了,請糾正我,但據我瞭解;它與使用多線程以及Java Swing如何解釋這些線程有關。我也收集以上代碼用於在創建窗口前確保所有線程都是'安全'的,因此invokeLater?

我已閱讀:

「你只能調用框架上運營從事件分派線程方法」

,只有在某些情況下,你可以調用的方法是在主方法的框架上進行操作。

能有人請澄清我正是事件派發線程是什麼?

它與多線程執行以及這些線程如何不安全地從主方法調用?另外爲什麼我們需要這個invokeLater?

難道我們不能只是創建窗口,任何其他對象?

我已經打了一下路障在我的研究,我沒有把握這些關係和想法。

一個側面說明的是,我想立足於深入瞭解我的知識,因爲我相信這將導致最佳的整體結果,結果的最佳方案。如果我深入瞭解某些工作是如何進行的,那麼您可以有效地使用提示和調整,而不是僅僅將它們重新編碼到代碼中,所以請不要害怕給我一些額外的深入解釋並拓寬我的知識。

謝謝。

回答

54

EventDispatching線程是一個由AWT管理的特殊線程。基本上它是一個在無限循環處理事件中運行的線程。 java.awt.EventQueue.invokeLater方法是提供一些將在事件隊列上運行的代碼的特殊方式。編寫一個在多線程環境中安全的ui框架非常困難,所以AWT作者決定他們只允許在一個特殊線程上進行GUI對象的操作。所有事件處理程序都將在此線程上執行,並且所有修改gui的代碼也應該在此線程上運行。

現在,AWT通常不會檢查您是否從其他線程發出GUI命令(C#的WPF框架確實會這樣做)。所以有可能編寫大量的代碼,並且對此非常不可知,並且不會遇到任何問題。但是這可能會導致未定義的行爲,所以最好的做法是始終確保gui代碼在事件分派器線程上運行。 invokeLater提供了一個機制來做到這一點。

所以一個典型的例子是,你需要運行一個長期運行的操作,如下載文件。所以你啓動一個線程來執行這個動作,然後當它完成時你將使用invokeLater來更新UI。如果您沒有使用invokeLater,而是直接更新了UI,則可能會出現競爭條件並可能發生未定義的行爲。

維基百科有更多信息:http://en.wikipedia.org/wiki/Event_dispatching_thread

此外,如果你很好奇,爲什麼AWT作者不只是在這裏做多線程工具包是一個很好的文章:https://community.oracle.com/blogs/kgh/2004/10/19/multithreaded-toolkits-failed-dream

+0

我道歉這麼晚纔回復,我一直保持着工作。你的文章其實很簡潔地回答了我的很多問題,所以我想爲此感謝你。 好吧,如果我理解正確,那麼爲了在GUI上進行操作,我應該對可運行對象使用invokeLater()方法,通過這樣做我可以確保始終使用EDT? 我還讀了關於現在正式支持的SwingWorker類。這個類會被認爲優於invokeLater方法還是我誤解,他們解決了兩個不同的問題? – linuscash

+1

有很多情況下,您可以確保已經在EDT上執行了例如事件處理程序(ActionListeners,ClickListeners),因此不需要從那裏使用invokeLater。我認爲一個SwingWorker只是一個具有與EDT交互的特殊機制的線程(可能通過invokeLater)。所以我肯定會在適當的時候使用它。 – luke

+0

好的,這很有道理,非常感謝。你已經爲我清除了很多差異。 – linuscash

11

EventDispatchThread(EDT)是特殊的線程保留僅用於Swing GUI和* Swing的相關事件,例如創建/修改/更新Swing JComponents,多爲常見問題herehere

所有輸出從BackGround Tasks的GUI,Runnable#Thread必須被包裹成invokeLater(),從同步的對象爲invokeAndWait();